codemp/game/g_vehicleTurret.c File Reference

#include "g_headers.h"
#include "bg_vehicles.h"
#include "b_local.h"
#include "../ghoul2/G2.h"

Go to the source code of this file.

Functions

void G_SetEnemy (gentity_t *self, gentity_t *enemy)
void WP_CalcVehMuzzle (gentity_t *ent, int muzzleNum)
gentity_tWP_FireVehicleWeapon (gentity_t *ent, vec3_t start, vec3_t dir, vehWeaponInfo_t *vehWeapon, qboolean alt_fire, qboolean isTurretWeap)
void G_VehMuzzleFireFX (gentity_t *ent, gentity_t *broadcaster, int muzzlesFired)
void VEH_TurretCheckFire (Vehicle_t *pVeh, gentity_t *parent, turretStats_t *turretStats, vehWeaponInfo_t *vehWeapon, int turretNum, int curMuzzle)
void VEH_TurretAnglesToEnemy (Vehicle_t *pVeh, int curMuzzle, float fSpeed, gentity_t *turretEnemy, qboolean bAILead, vec3_t desiredAngles)
qboolean VEH_TurretAim (Vehicle_t *pVeh, gentity_t *parent, gentity_t *turretEnemy, turretStats_t *turretStats, vehWeaponInfo_t *vehWeapon, int turretNum, int curMuzzle, vec3_t desiredAngles)
void VEH_TurretObeyPassengerControl (Vehicle_t *pVeh, gentity_t *parent, int turretNum)
void VEH_TurretThink (Vehicle_t *pVeh, gentity_t *parent, int turretNum)


Function Documentation

void G_SetEnemy gentity_t self,
gentity_t enemy
 

void G_VehMuzzleFireFX gentity_t ent,
gentity_t broadcaster,
int  muzzlesFired
 

Definition at line 3836 of file g_weapon.c.

References gentity_s::client, EV_VEH_FIRE, G_AddEvent(), G_TempEntity(), gentity_t, gentity_s::m_pVehicle, entityState_s::number, playerState_s::origin, entityState_s::owner, gclient_s::ps, gentity_s::s, entityState_s::trickedentindex, and Vehicle_t.

Referenced by FireVehicleWeapon(), and VEH_TurretCheckFire().

03837 {
03838         Vehicle_t *pVeh = ent->m_pVehicle;
03839         gentity_t *b;
03840 
03841         if (!pVeh)
03842         {
03843                 return;
03844         }
03845 
03846         if (!broadcaster)
03847         { //oh well. We will WASTE A TEMPENT.
03848                 b = G_TempEntity( ent->client->ps.origin, EV_VEH_FIRE );
03849         }
03850         else
03851         { //joy
03852                 b = broadcaster;
03853         }
03854 
03855         //this guy owns it
03856         b->s.owner = ent->s.number;
03857 
03858         //this is the bitfield of all muzzles fired this time
03859         //NOTE: just need MAX_VEHICLE_MUZZLES bits for this... should be cool since it's currently 12 and we're sending it in 16 bits
03860         b->s.trickedentindex = muzzlesFired;
03861 
03862         if ( broadcaster )
03863         { //add the event
03864                 G_AddEvent( b, EV_VEH_FIRE, 0 );
03865         }
03866 }

qboolean VEH_TurretAim Vehicle_t pVeh,
gentity_t parent,
gentity_t turretEnemy,
turretStats_t turretStats,
vehWeaponInfo_t vehWeapon,
int  turretNum,
int  curMuzzle,
vec3_t  desiredAngles
 

Definition at line 89 of file g_vehicleTurret.c.

References AngleNormalize180(), AnglesSubtract(), turretStats_t::bAILead, vehWeaponInfo_t::fSpeed, turretStats_t::fTurnSpeed, gentity_t, Vehicle_s::m_iMuzzleTime, Vehicle_s::m_pVehicleInfo, Vehicle_s::m_vMuzzleDir, Vehicle_s::m_vOrientation, NPC_SetBoneAngles(), PITCH, turretStats_t::pitchAxis, turretStats_t::pitchBone, turretStats_t::pitchClampDown, turretStats_t::pitchClampUp, qboolean, qfalse, qtrue, vehicleInfo_t::turret, vec3_t, vectoangles(), VectorClear, VEH_TurretAnglesToEnemy(), Vehicle_t, WP_CalcVehMuzzle(), YAW, turretStats_t::yawAxis, turretStats_t::yawBone, turretStats_t::yawClampLeft, and turretStats_t::yawClampRight.

Referenced by VEH_TurretObeyPassengerControl(), and VEH_TurretThink().

00096 {
00097         vec3_t  curAngles, addAngles, newAngles, yawAngles, pitchAngles;
00098         float   aimCorrect = qfalse;
00099 
00100         WP_CalcVehMuzzle( parent, curMuzzle );
00101         //get the current absolute angles of the turret right now
00102         vectoangles( pVeh->m_vMuzzleDir[curMuzzle], curAngles );
00103         //subtract out the vehicle's angles to get the relative alignment
00104         AnglesSubtract( curAngles, pVeh->m_vOrientation, curAngles );
00105 
00106         if ( turretEnemy )
00107         {
00108                 aimCorrect = qtrue;
00109                 // ...then we'll calculate what new aim adjustments we should attempt to make this frame
00110                 // Aim at enemy
00111                 VEH_TurretAnglesToEnemy( pVeh, curMuzzle, vehWeapon->fSpeed, turretEnemy, turretStats->bAILead, desiredAngles ); 
00112         }
00113         //subtract out the vehicle's angles to get the relative desired alignment
00114         AnglesSubtract( desiredAngles, pVeh->m_vOrientation, desiredAngles );
00115         //Now clamp the desired relative angles
00116         //clamp yaw
00117         desiredAngles[YAW] = AngleNormalize180( desiredAngles[YAW] );
00118         if ( pVeh->m_pVehicleInfo->turret[turretNum].yawClampLeft
00119                 && desiredAngles[YAW] > pVeh->m_pVehicleInfo->turret[turretNum].yawClampLeft )
00120         {
00121                 aimCorrect = qfalse;
00122                 desiredAngles[YAW] = pVeh->m_pVehicleInfo->turret[turretNum].yawClampLeft;
00123         }
00124         if ( pVeh->m_pVehicleInfo->turret[turretNum].yawClampRight
00125                 && desiredAngles[YAW] < pVeh->m_pVehicleInfo->turret[turretNum].yawClampRight )
00126         {
00127                 aimCorrect = qfalse;
00128                 desiredAngles[YAW] = pVeh->m_pVehicleInfo->turret[turretNum].yawClampRight;
00129         }
00130         //clamp pitch
00131         desiredAngles[PITCH] = AngleNormalize180( desiredAngles[PITCH] );
00132         if ( pVeh->m_pVehicleInfo->turret[turretNum].pitchClampDown
00133                 && desiredAngles[PITCH] > pVeh->m_pVehicleInfo->turret[turretNum].pitchClampDown )
00134         {
00135                 aimCorrect = qfalse;
00136                 desiredAngles[PITCH] = pVeh->m_pVehicleInfo->turret[turretNum].pitchClampDown;
00137         }
00138         if ( pVeh->m_pVehicleInfo->turret[turretNum].pitchClampUp
00139                 && desiredAngles[PITCH] < pVeh->m_pVehicleInfo->turret[turretNum].pitchClampUp )
00140         {
00141                 aimCorrect = qfalse;
00142                 desiredAngles[PITCH] = pVeh->m_pVehicleInfo->turret[turretNum].pitchClampUp;
00143         }
00144         //Now get the offset we want from our current relative angles
00145         AnglesSubtract( desiredAngles, curAngles, addAngles );
00146         //Now cap the addAngles for our fTurnSpeed
00147         if ( addAngles[PITCH] > turretStats->fTurnSpeed )
00148         {
00149                 //aimCorrect = qfalse;//???
00150                 addAngles[PITCH] = turretStats->fTurnSpeed;
00151         }
00152         else if ( addAngles[PITCH] < -turretStats->fTurnSpeed )
00153         {
00154                 //aimCorrect = qfalse;//???
00155                 addAngles[PITCH] = -turretStats->fTurnSpeed;
00156         }
00157         if ( addAngles[YAW] > turretStats->fTurnSpeed )
00158         {
00159                 //aimCorrect = qfalse;//???
00160                 addAngles[YAW] = turretStats->fTurnSpeed;
00161         }
00162         else if ( addAngles[YAW] < -turretStats->fTurnSpeed )
00163         {
00164                 //aimCorrect = qfalse;//???
00165                 addAngles[YAW] = -turretStats->fTurnSpeed;
00166         }
00167         //Now add the additional angles back in to our current relative angles
00168         //FIXME: add some AI aim error randomness...?
00169         newAngles[PITCH] = AngleNormalize180( curAngles[PITCH]+addAngles[PITCH] );
00170         newAngles[YAW] = AngleNormalize180( curAngles[YAW]+addAngles[YAW] );
00171         //Now set the bone angles to the new angles
00172         //set yaw
00173         if ( turretStats->yawBone )
00174         {
00175                 VectorClear( yawAngles );
00176                 yawAngles[turretStats->yawAxis] = newAngles[YAW];
00177                 NPC_SetBoneAngles( parent, turretStats->yawBone, yawAngles );
00178         }
00179         //set pitch
00180         if ( turretStats->pitchBone )
00181         {
00182                 VectorClear( pitchAngles );
00183                 pitchAngles[turretStats->pitchAxis] = newAngles[PITCH];
00184                 NPC_SetBoneAngles( parent, turretStats->pitchBone, pitchAngles );
00185         }
00186         //force muzzle to recalc next check
00187         pVeh->m_iMuzzleTime[curMuzzle] = 0;
00188 
00189         return aimCorrect;
00190 }

void VEH_TurretAnglesToEnemy Vehicle_t pVeh,
int  curMuzzle,
float  fSpeed,
gentity_t turretEnemy,
qboolean  bAILead,
vec3_t  desiredAngles
 

Definition at line 61 of file g_vehicleTurret.c.

References gentity_s::client, entityShared_t::currentOrigin, gentity_t, Vehicle_s::m_vMuzzlePos, entityState_s::pos, gclient_s::ps, gentity_s::r, gentity_s::s, trajectory_t::trDelta, vec3_t, vectoangles(), VectorCopy, VectorMA, VectorNormalize(), VectorSubtract, Vehicle_t, and playerState_s::velocity.

Referenced by VEH_TurretAim().

00062 {
00063         vec3_t  enemyDir, org;
00064         VectorCopy( turretEnemy->r.currentOrigin, org );
00065         if ( bAILead )
00066         {//we want to lead them a bit
00067                 vec3_t diff, velocity;
00068                 float dist;
00069                 VectorSubtract( org, pVeh->m_vMuzzlePos[curMuzzle], diff );
00070                 dist = VectorNormalize( diff );
00071                 if ( turretEnemy->client )
00072                 {
00073                         VectorCopy( turretEnemy->client->ps.velocity, velocity );
00074                 }
00075                 else
00076                 {
00077                         VectorCopy( turretEnemy->s.pos.trDelta, velocity );
00078                 }
00079                 VectorMA( org, (dist/fSpeed), velocity, org );
00080         }
00081 
00082         //FIXME: this isn't quite right, it's aiming from the muzzle, not the center of the turret...
00083         VectorSubtract( org, pVeh->m_vMuzzlePos[curMuzzle], enemyDir );
00084         //Get the desired absolute, world angles to our target
00085         vectoangles( enemyDir, desiredAngles );
00086 }

void VEH_TurretCheckFire Vehicle_t pVeh,
gentity_t parent,
turretStats_t turretStats,
vehWeaponInfo_t vehWeapon,
int  turretNum,
int  curMuzzle
 

Definition at line 12 of file g_vehicleTurret.c.

References vehTurretStatus_t::ammo, G_VehMuzzleFireFX(), gentity_t, vehWeaponInfo_t::iAmmoPerShot, turretStats_t::iDelay, turretStats_t::iMuzzle, level, Vehicle_s::m_iMuzzleTag, Vehicle_s::m_iMuzzleWait, Vehicle_s::m_pVehicleInfo, Vehicle_s::m_vMuzzleDir, Vehicle_s::m_vMuzzlePos, vehTurretStatus_t::nextMuzzle, qtrue, level_locals_t::time, vehicleInfo_t::turret, Vehicle_s::turretStatus, Vehicle_t, WP_CalcVehMuzzle(), and WP_FireVehicleWeapon().

Referenced by VEH_TurretObeyPassengerControl(), and VEH_TurretThink().

00018 {
00019         // if it's time to fire and we have an enemy, then gun 'em down!  pushDebounce time controls next fire time
00020         if ( pVeh->m_iMuzzleTag[curMuzzle] == -1 )
00021         {//invalid muzzle?
00022                 return;
00023         }
00024         
00025         if ( pVeh->m_iMuzzleWait[curMuzzle] >= level.time )
00026         {//can't fire yet
00027                 return;
00028         }
00029 
00030         if ( pVeh->turretStatus[turretNum].ammo < vehWeapon->iAmmoPerShot )
00031         {//no ammo, can't fire
00032                 return;
00033         }
00034         
00035         //if ( turretEnemy )
00036         {
00037                 //FIXME: check to see if I'm aiming generally where I want to
00038                 int nextMuzzle = 0, muzzlesFired = (1<<curMuzzle);
00039                 gentity_t *missile;
00040                 WP_CalcVehMuzzle( parent, curMuzzle );
00041 
00042                 //FIXME: some variation in fire dir
00043                 missile = WP_FireVehicleWeapon( parent, pVeh->m_vMuzzlePos[curMuzzle], pVeh->m_vMuzzleDir[curMuzzle], vehWeapon, (turretNum!=0), qtrue );
00044 
00045                 //play the weapon's muzzle effect if we have one
00046                 G_VehMuzzleFireFX(parent, missile, muzzlesFired );
00047 
00048                 //take the ammo away
00049                 pVeh->turretStatus[turretNum].ammo -= vehWeapon->iAmmoPerShot;
00050                 //toggle to the next muzzle on this turret, if there is one
00051                 nextMuzzle = ((curMuzzle+1)==pVeh->m_pVehicleInfo->turret[turretNum].iMuzzle[0])?pVeh->m_pVehicleInfo->turret[turretNum].iMuzzle[1]:pVeh->m_pVehicleInfo->turret[turretNum].iMuzzle[0];
00052                 if ( nextMuzzle )
00053                 {//a valid muzzle to toggle to
00054                         pVeh->turretStatus[turretNum].nextMuzzle = nextMuzzle-1;//-1 because you type muzzles 1-10 in the .veh file
00055                 }
00056                 //add delay to the next muzzle so it doesn't fire right away on the next frame
00057                 pVeh->m_iMuzzleWait[pVeh->turretStatus[turretNum].nextMuzzle] = level.time + turretStats->iDelay;
00058         }
00059 }

void VEH_TurretObeyPassengerControl Vehicle_t pVeh,
gentity_t parent,
int  turretNum
 

Definition at line 304 of file g_vehicleTurret.c.

References BUTTON_ALT_ATTACK, BUTTON_ATTACK, usercmd_s::buttons, gentity_s::client, clientPersistant_t::cmd, g_vehWeaponInfo, gentity_t, gentity_s::health, turretStats_t::iWeapon, Vehicle_s::m_ppPassengers, Vehicle_s::m_pVehicleInfo, vehTurretStatus_t::nextMuzzle, NULL, turretStats_t::passengerNum, gclient_s::pers, gclient_s::ps, vehicleInfo_t::turret, Vehicle_s::turretStatus, vec3_t, VectorCopy, VEH_TurretAim(), VEH_TurretCheckFire(), Vehicle_t, and playerState_s::viewangles.

Referenced by VEH_TurretThink().

00305 {
00306         turretStats_t *turretStats = &pVeh->m_pVehicleInfo->turret[turretNum];
00307         gentity_t *passenger = (gentity_t *)pVeh->m_ppPassengers[turretStats->passengerNum-1];
00308 
00309         if ( passenger && passenger->client && passenger->health > 0 )
00310         {//a valid, living passenger client
00311                 vehWeaponInfo_t *vehWeapon = &g_vehWeaponInfo[turretStats->iWeapon];
00312                 int     curMuzzle = pVeh->turretStatus[turretNum].nextMuzzle;
00313                 vec3_t aimAngles;
00314                 VectorCopy( passenger->client->ps.viewangles, aimAngles );
00315 
00316                 VEH_TurretAim( pVeh, parent, NULL, turretStats, vehWeapon, turretNum, curMuzzle, aimAngles );
00317                 if ( (passenger->client->pers.cmd.buttons&(BUTTON_ATTACK|BUTTON_ALT_ATTACK)) )
00318                 {//he's pressing an attack button, so fire!
00319                         VEH_TurretCheckFire( pVeh, parent, turretStats, vehWeapon, turretNum, curMuzzle );
00320                 }
00321         }
00322 }

void VEH_TurretThink Vehicle_t pVeh,
gentity_t parent,
int  turretNum
 

Definition at line 324 of file g_vehicleTurret.c.

References trace_t::allsolid, turretStats_t::bAI, gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, enemyDist, vehTurretStatus_t::enemyEntNum, vehTurretStatus_t::enemyHoldTime, trace_t::entityNum, ENTITYNUM_NONE, ENTITYNUM_WORLD, turretStats_t::fAIRange, g_entities, g_vehWeaponInfo, gentity_t, gentity_s::health, turretStats_t::iAmmoMax, gentity_s::inuse, turretStats_t::iWeapon, level, Vehicle_s::m_iNumPassengers, Vehicle_s::m_pPilot, Vehicle_s::m_pVehicleInfo, Vehicle_s::m_vMuzzlePos, MASK_SHOT, vehTurretStatus_t::nextMuzzle, NULL, entityState_s::number, entityShared_t::ownerNum, turretStats_t::passengerNum, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, trace_t::startsolid, TEAM_SPECTATOR, level_locals_t::time, trap_InPVS(), trap_Trace(), vehicleInfo_t::turret, Vehicle_s::turretStatus, vec3_t, VectorCopy, VectorSubtract, VEH_TurretAim(), VEH_TurretCheckFire(), VEH_TurretObeyPassengerControl(), Vehicle_t, and WP_CalcVehMuzzle().

00326 {
00327         qboolean        doAim = qfalse;
00328         float           enemyDist, rangeSq;
00329         vec3_t          enemyDir;
00330         turretStats_t *turretStats = &pVeh->m_pVehicleInfo->turret[turretNum];
00331         vehWeaponInfo_t *vehWeapon = NULL;
00332         gentity_t       *turretEnemy = NULL;
00333         int                     curMuzzle = 0;//?
00334         
00335 
00336         if ( !turretStats || !turretStats->iAmmoMax )
00337         {//not a valid turret
00338                 return;
00339         }
00340         
00341         if ( turretStats->passengerNum 
00342                 && pVeh->m_iNumPassengers >= turretStats->passengerNum )
00343         {//the passenger that has control of this turret is on the ship
00344                 VEH_TurretObeyPassengerControl( pVeh, parent, turretNum );
00345                 return;
00346         }
00347         else if ( !turretStats->bAI )//try AI
00348         {//this turret does not think on its own.
00349                 return;
00350         }
00351 
00352         vehWeapon = &g_vehWeaponInfo[turretStats->iWeapon];
00353         rangeSq = (turretStats->fAIRange*turretStats->fAIRange);
00354         curMuzzle = pVeh->turretStatus[turretNum].nextMuzzle;
00355 
00356         if ( pVeh->turretStatus[turretNum].enemyEntNum < ENTITYNUM_WORLD )
00357         {
00358                 turretEnemy = &g_entities[pVeh->turretStatus[turretNum].enemyEntNum];
00359                 if ( turretEnemy->health < 0 
00360                         || !turretEnemy->inuse
00361                         || turretEnemy == ((gentity_t*)pVeh->m_pPilot)//enemy became my pilot///?
00362                         || turretEnemy == parent
00363                         || turretEnemy->r.ownerNum == parent->s.number // a passenger?
00364                         || ( turretEnemy->client && turretEnemy->client->sess.sessionTeam == TEAM_SPECTATOR ) )
00365                 {//don't keep going after spectators, pilot, self, dead people, etc.
00366                         turretEnemy = NULL;
00367                         pVeh->turretStatus[turretNum].enemyEntNum = ENTITYNUM_NONE;
00368                 }
00369         }
00370 
00371         if ( pVeh->turretStatus[turretNum].enemyHoldTime < level.time )
00372         {
00373                 if ( VEH_TurretFindEnemies( pVeh, parent, turretStats, turretNum, curMuzzle ) )
00374                 {
00375                         turretEnemy = &g_entities[pVeh->turretStatus[turretNum].enemyEntNum];
00376                         doAim = qtrue;
00377                 }
00378                 else if ( parent->enemy && parent->enemy->s.number < ENTITYNUM_WORLD )
00379                 {
00380                         turretEnemy = parent->enemy;
00381                         doAim = qtrue;
00382                 }
00383                 if ( turretEnemy )
00384                 {//found one
00385                         if ( turretEnemy->client )
00386                         {//hold on to clients for a min of 3 seconds
00387                                 pVeh->turretStatus[turretNum].enemyHoldTime = level.time + 3000;
00388                         }
00389                         else
00390                         {//hold less
00391                                 pVeh->turretStatus[turretNum].enemyHoldTime = level.time + 500;
00392                         }
00393                 }
00394         }
00395         if ( turretEnemy != NULL )
00396         {
00397                 if ( turretEnemy->health > 0 )
00398                 {
00399                         // enemy is alive
00400                         WP_CalcVehMuzzle( parent, curMuzzle );
00401                         VectorSubtract( turretEnemy->r.currentOrigin, pVeh->m_vMuzzlePos[curMuzzle], enemyDir );
00402                         enemyDist = VectorLengthSquared( enemyDir );
00403 
00404                         if ( enemyDist < rangeSq )
00405                         {
00406                                 // was in valid radius
00407                                 if ( trap_InPVS( pVeh->m_vMuzzlePos[curMuzzle], turretEnemy->r.currentOrigin ) )
00408                                 {
00409                                         // Every now and again, check to see if we can even trace to the enemy
00410                                         trace_t tr;
00411                                         vec3_t start, end;
00412                                         VectorCopy( pVeh->m_vMuzzlePos[curMuzzle], start );
00413 
00414                                         VectorCopy( turretEnemy->r.currentOrigin, end );
00415                                         trap_Trace( &tr, start, NULL, NULL, end, parent->s.number, MASK_SHOT );
00416 
00417                                         if ( tr.entityNum == turretEnemy->s.number
00418                                                 || (!tr.allsolid && !tr.startsolid ) )
00419                                         {
00420                                                 doAim = qtrue;  // Can see our enemy
00421                                         }
00422                                 }
00423                         }
00424                 }
00425         }
00426 
00427         if ( doAim )
00428         {
00429                 vec3_t aimAngles;
00430                 if ( VEH_TurretAim( pVeh, parent, turretEnemy, turretStats, vehWeapon, turretNum, curMuzzle, aimAngles ) )
00431                 {
00432                         VEH_TurretCheckFire( pVeh, parent, /*turretEnemy,*/ turretStats, vehWeapon, turretNum, curMuzzle );
00433                 }
00434         }
00435 }

void WP_CalcVehMuzzle gentity_t ent,
int  muzzleNum
 

Definition at line 3575 of file g_weapon.c.

References gentity_s::client, gentity_t, gentity_s::ghoul2, level, Vehicle_s::m_iMuzzleTag, Vehicle_s::m_iMuzzleTime, gentity_s::m_pVehicle, Vehicle_s::m_pVehicleInfo, Vehicle_s::m_vMuzzleDir, Vehicle_s::m_vMuzzlePos, gentity_s::modelScale, NEGATIVE_Y, NULL, playerState_s::origin, ORIGIN, PITCH, gclient_s::ps, ROLL, level_locals_t::time, trap_G2API_GetBoltMatrix_NoRecNoRot(), vehicleInfo_t::type, vec3_t, VectorCopy, Vehicle_t, VH_ANIMAL, VH_SPEEDER, VH_WALKER, and playerState_s::viewangles.

Referenced by FireVehicleWeapon(), VEH_TurretAim(), VEH_TurretCheckFire(), and VEH_TurretThink().

03576 {
03577         Vehicle_t *pVeh = ent->m_pVehicle;
03578         mdxaBone_t boltMatrix;
03579         vec3_t  vehAngles;
03580 
03581         assert(pVeh);
03582 
03583         if (pVeh->m_iMuzzleTime[muzzleNum] == level.time)
03584         { //already done for this frame, don't need to do it again
03585                 return;
03586         }
03587         //Uh... how about we set this, hunh...?  :)
03588         pVeh->m_iMuzzleTime[muzzleNum] = level.time;
03589         
03590         VectorCopy( ent->client->ps.viewangles, vehAngles );
03591         if ( pVeh->m_pVehicleInfo
03592                 && (pVeh->m_pVehicleInfo->type == VH_ANIMAL
03593                          ||pVeh->m_pVehicleInfo->type == VH_WALKER
03594                          ||pVeh->m_pVehicleInfo->type == VH_SPEEDER) )
03595         {
03596                 vehAngles[PITCH] = vehAngles[ROLL] = 0;
03597         }
03598 
03599         trap_G2API_GetBoltMatrix_NoRecNoRot(ent->ghoul2, 0, pVeh->m_iMuzzleTag[muzzleNum], &boltMatrix, vehAngles,
03600                 ent->client->ps.origin, level.time, NULL, ent->modelScale);
03601         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, pVeh->m_vMuzzlePos[muzzleNum]);
03602         BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, pVeh->m_vMuzzleDir[muzzleNum]);
03603 }

gentity_t* WP_FireVehicleWeapon gentity_t ent,
vec3_t  start,
vec3_t  dir,
vehWeaponInfo_t vehWeapon,
qboolean  alt_fire,
qboolean  isTurretWeap
 

Definition at line 3623 of file g_weapon.c.

References gentity_s::angle, vehWeaponInfo_t::bExplodeOnExpire, vehWeaponInfo_t::bHasGravity, vehWeaponInfo_t::bIonWeapon, vehWeaponInfo_t::bIsProjectile, gentity_s::bounceCount, vehWeaponInfo_t::bSaberBlockable, CLASS_VEHICLE, gentity_s::classname, gentity_s::client, gentity_s::clipmask, entityShared_t::contents, CONTENTS_LIGHTSABER, CreateMissile(), gentity_s::damage, DAMAGE_DEATH_KNOCKBACK, gentity_s::dflags, gentity_s::die, EF_ALT_FIRING, EF_JETPACK_ACTIVE, EF_RADAROBJECT, entityState_s::eFlags, gentity_s::enemy, ENTITYNUM_NONE, vehWeaponInfo_t::fHeight, vehWeaponInfo_t::fHoming, vehWeaponInfo_t::fHomingFOV, vehWeaponInfo_t::fSpeed, vehWeaponInfo_t::fSplashRadius, vehWeaponInfo_t::fWidth, g_entities, G_ExplodeMissile(), G_FreeEntity(), G_SetOrigin(), g_vehWeaponInfo, entityState_s::genericenemyindex, gentity_s::genericValue1, gentity_s::genericValue2, gentity_t, gentity_s::health, vehWeaponInfo_t::iDamage, vehWeaponInfo_t::iHealth, vehWeaponInfo_t::iLifeTime, vehWeaponInfo_t::iLockOnTime, vehWeaponInfo_t::iSplashDamage, level, Vehicle_s::m_pPilot, gentity_s::m_pVehicle, MASK_SHOT, gentity_s::mass, MAX_GENTITIES, entityShared_t::maxs, gentity_s::methodOfDeath, entityShared_t::mins, MOD_VEHICLE, gentity_s::movedir, gentity_s::nextthink, entityState_s::NPC_class, NULL, entityState_s::number, OnSameTeam(), entityState_s::otherEntityNum, entityState_s::otherEntityNum2, entityState_s::owner, entityShared_t::ownerNum, entityState_s::pos, gclient_s::ps, qfalse, qtrue, gentity_s::r, gentity_s::radius, gentity_s::random, RocketDie(), playerState_s::rocketLastValidTime, playerState_s::rocketLockIndex, playerState_s::rocketLockTime, rocketThink(), gentity_s::s, bgEntity_s::s, gentity_s::spawnflags, gentity_s::speed, gentity_s::splashDamage, gentity_s::splashMethodOfDeath, gentity_s::splashRadius, gentity_s::takedamage, gentity_s::think, level_locals_t::time, gentity_s::touch, TR_GRAVITY, trajectory_t::trType, vec3_t, VectorCopy, VectorScale, VectorSet, VEH_HOMING_MISSILE_THINK_TIME, entityState_s::weapon, WP_BLASTER, WP_DEMP2, WP_ROCKET_LAUNCHER, WP_THERMAL, WP_TouchVehMissile(), WP_TURRET, and WP_VehWeapSetSolidToOwner().

Referenced by FireVehicleWeapon(), and VEH_TurretCheckFire().

03624 {
03625         gentity_t       *missile = NULL;
03626 
03627         //FIXME: add some randomness...?  Inherent inaccuracy stat of weapon?  Pilot skill?
03628         if ( !vehWeapon )
03629         {//invalid vehicle weapon
03630                 return NULL;
03631         }
03632         else if ( vehWeapon->bIsProjectile )
03633         {//projectile entity
03634                 vec3_t          mins, maxs;
03635 
03636                 VectorSet( maxs, vehWeapon->fWidth/2.0f,vehWeapon->fWidth/2.0f,vehWeapon->fHeight/2.0f );
03637                 VectorScale( maxs, -1, mins );
03638 
03639                 //make sure our start point isn't on the other side of a wall
03640                 WP_TraceSetStart( ent, start, mins, maxs );
03641                 
03642                 //FIXME: CUSTOM MODEL?
03643                 //QUERY: alt_fire true or not?  Does it matter?
03644                 missile = CreateMissile( start, dir, vehWeapon->fSpeed, 10000, ent, qfalse );
03645 
03646                 missile->classname = "vehicle_proj";
03647                 
03648                 missile->s.genericenemyindex = ent->s.number+MAX_GENTITIES;
03649                 missile->damage = vehWeapon->iDamage;
03650                 missile->splashDamage = vehWeapon->iSplashDamage;
03651                 missile->splashRadius = vehWeapon->fSplashRadius;
03652 
03653                 //FIXME: externalize some of these properties?
03654                 missile->dflags = DAMAGE_DEATH_KNOCKBACK;
03655                 missile->clipmask = MASK_SHOT;
03656                 //Maybe by checking flags...?
03657                 if ( vehWeapon->bSaberBlockable )
03658                 {
03659                         missile->clipmask |= CONTENTS_LIGHTSABER;
03660                 }
03661                 /*
03662                 if ( (vehWeapon->iFlags&VWF_KNOCKBACK) )
03663                 {
03664                         missile->dflags &= ~DAMAGE_DEATH_KNOCKBACK;
03665                 }
03666                 if ( (vehWeapon->iFlags&VWF_RADAR) )
03667                 {
03668                         missile->s.eFlags |= EF_RADAROBJECT;
03669                 }
03670                 */
03671                 // Make it easier to hit things
03672                 VectorCopy( mins, missile->r.mins );
03673                 VectorCopy( maxs, missile->r.maxs );
03674                 //some slightly different stuff for things with bboxes
03675                 if ( vehWeapon->fWidth || vehWeapon->fHeight )
03676                 {//we assume it's a rocket-like thing
03677                         missile->s.weapon = WP_ROCKET_LAUNCHER;//does this really matter?
03678                         missile->methodOfDeath = MOD_VEHICLE;//MOD_ROCKET;
03679                         missile->splashMethodOfDeath = MOD_VEHICLE;//MOD_ROCKET;// ?SPLASH;
03680 
03681                         // we don't want it to ever bounce
03682                         missile->bounceCount = 0;
03683 
03684                         missile->mass = 10;
03685                 }
03686                 else
03687                 {//a blaster-laser-like thing
03688                         missile->s.weapon = WP_BLASTER;//does this really matter?
03689                         missile->methodOfDeath = MOD_VEHICLE; //count as a heavy weap
03690                         missile->splashMethodOfDeath = MOD_VEHICLE;// ?SPLASH;
03691                         // we don't want it to bounce forever
03692                         missile->bounceCount = 8;
03693                 }
03694                 
03695                 if ( vehWeapon->bHasGravity )
03696                 {//TESTME: is this all we need to do?
03697                         missile->s.weapon = WP_THERMAL;//does this really matter?
03698                         missile->s.pos.trType = TR_GRAVITY;
03699                 }
03700                 
03701                 if ( vehWeapon->bIonWeapon )
03702                 {//so it disables ship shields and sends them out of control
03703                         missile->s.weapon = WP_DEMP2;
03704                 }
03705 
03706                 if ( vehWeapon->iHealth )
03707                 {//the missile can take damage
03708                         missile->health = vehWeapon->iHealth;
03709                         missile->takedamage = qtrue;
03710                         missile->r.contents = MASK_SHOT;
03711                         missile->die = RocketDie;
03712                 }
03713 
03714                 //pilot should own this projectile on server if we have a pilot
03715                 if (ent->m_pVehicle && ent->m_pVehicle->m_pPilot)
03716                 {//owned by vehicle pilot
03717                         missile->r.ownerNum = ent->m_pVehicle->m_pPilot->s.number;
03718                 }
03719                 else
03720                 {//owned by vehicle?
03721                         missile->r.ownerNum = ent->s.number;
03722                 }
03723 
03724                 //set veh as cgame side owner for purpose of fx overrides
03725                 missile->s.owner = ent->s.number;
03726                 if ( alt_fire )
03727                 {//use the second weapon's iShotFX
03728                         missile->s.eFlags |= EF_ALT_FIRING;
03729                 }
03730                 if ( isTurretWeap )
03731                 {//look for the turret weapon info on cgame side, not vehicle weapon info
03732                         missile->s.weapon = WP_TURRET;
03733                 }
03734                 if ( vehWeapon->iLifeTime )
03735                 {//expire after a time
03736                         if ( vehWeapon->bExplodeOnExpire )
03737                         {//blow up when your lifetime is up
03738                                 missile->think = G_ExplodeMissile;//FIXME: custom func?
03739                         }
03740                         else
03741                         {//just remove yourself
03742                                 missile->think = G_FreeEntity;//FIXME: custom func?
03743                         }
03744                         missile->nextthink = level.time + vehWeapon->iLifeTime;
03745                 }
03746                 missile->s.otherEntityNum2 = (vehWeapon-&g_vehWeaponInfo[0]);
03747                 missile->s.eFlags |= EF_JETPACK_ACTIVE;
03748                 //homing
03749                 if ( vehWeapon->fHoming )
03750                 {//homing missile
03751                         if ( ent->client && ent->client->ps.rocketLockIndex != ENTITYNUM_NONE )
03752                         {
03753                                 int dif = 0;
03754                                 float rTime;
03755                                 rTime = ent->client->ps.rocketLockTime;
03756 
03757                                 if (rTime == -1)
03758                                 {
03759                                         rTime = ent->client->ps.rocketLastValidTime;
03760                                 }
03761 
03762                                 if ( !vehWeapon->iLockOnTime )
03763                                 {//no minimum lock-on time
03764                                         dif = 10;//guaranteed lock-on
03765                                 }
03766                                 else
03767                                 {
03768                                         float lockTimeInterval = vehWeapon->iLockOnTime/16.0f;
03769                                         dif = ( level.time - rTime ) / lockTimeInterval;
03770                                 }
03771 
03772                                 if (dif < 0)
03773                                 {
03774                                         dif = 0;
03775                                 }
03776 
03777                                 //It's 10 even though it locks client-side at 8, because we want them to have a sturdy lock first, and because there's a slight difference in time between server and client
03778                                 if ( dif >= 10 && rTime != -1 )
03779                                 {
03780                                         missile->enemy = &g_entities[ent->client->ps.rocketLockIndex];
03781 
03782                                         if (missile->enemy && missile->enemy->client && missile->enemy->health > 0 && !OnSameTeam(ent, missile->enemy))
03783                                         { //if enemy became invalid, died, or is on the same team, then don't seek it
03784                                                 missile->spawnflags |= 1;//just to let it know it should be faster...
03785                                                 missile->speed = vehWeapon->fSpeed;
03786                                                 missile->angle = vehWeapon->fHoming;
03787                                                 missile->radius = vehWeapon->fHomingFOV;
03788                                                 //crap, if we have a lifetime, need to store that somewhere else on ent and have rocketThink func check it every frame...
03789                                                 if ( vehWeapon->iLifeTime )
03790                                                 {//expire after a time
03791                                                         missile->genericValue1 = level.time + vehWeapon->iLifeTime;
03792                                                         missile->genericValue2 = (int)(vehWeapon->bExplodeOnExpire);
03793                                                 }
03794                                                 //now go ahead and use the rocketThink func
03795                                                 missile->think = rocketThink;//FIXME: custom func?
03796                                                 missile->nextthink = level.time + VEH_HOMING_MISSILE_THINK_TIME;
03797                                                 missile->s.eFlags |= EF_RADAROBJECT;//FIXME: externalize
03798                                                 if ( missile->enemy->s.NPC_class == CLASS_VEHICLE )
03799                                                 {//let vehicle know we've locked on to them
03800                                                         missile->s.otherEntityNum = missile->enemy->s.number;
03801                                                 }
03802                                         }
03803                                 }
03804 
03805                                 VectorCopy( dir, missile->movedir );
03806                                 missile->random = 1.0f;//FIXME: externalize?
03807                         }
03808                 }
03809                 if ( !vehWeapon->fSpeed )
03810                 {//a mine or something?
03811                         //only do damage when someone touches us
03812                         missile->s.weapon = WP_THERMAL;//does this really matter?
03813                         G_SetOrigin( missile, start );
03814                         missile->touch = WP_TouchVehMissile;
03815                         missile->s.eFlags |= EF_RADAROBJECT;//FIXME: externalize
03816                         //crap, if we have a lifetime, need to store that somewhere else on ent and have rocketThink func check it every frame...
03817                         if ( vehWeapon->iLifeTime )
03818                         {//expire after a time
03819                                 missile->genericValue1 = vehWeapon->iLifeTime;
03820                                 missile->genericValue2 = (int)(vehWeapon->bExplodeOnExpire);
03821                         }
03822                         //now go ahead and use the setsolidtoowner func
03823                         missile->think = WP_VehWeapSetSolidToOwner;
03824                         missile->nextthink = level.time + 3000;
03825                 }
03826         }
03827         else
03828         {//traceline
03829                 //FIXME: implement
03830         }
03831 
03832         return missile;
03833 }