#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_t * | WP_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) |
|
||||||||||||
|
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||||||
|
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 }
|
|
||||||||||||||||||||||||||||
|
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 }
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||||||
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||||||||||||||||||
|
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 }
|