00001 #include "g_local.h"
00002 #include "../ghoul2/G2.h"
00003 #include "q_shared.h"
00004
00005 void G_SetEnemy( gentity_t *self, gentity_t *enemy );
00006 void finish_spawning_turretG2( gentity_t *base );
00007 void ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath );
00008 void turretG2_base_use( gentity_t *self, gentity_t *other, gentity_t *activator );
00009
00010
00011 #define SPF_TURRETG2_CANRESPAWN 4
00012 #define SPF_TURRETG2_TURBO 8
00013 #define SPF_TURRETG2_LEAD_ENEMY 16
00014 #define SPF_SHOWONRADAR 32
00015
00016 #define ARM_ANGLE_RANGE 60
00017 #define HEAD_ANGLE_RANGE 90
00018
00019 #define name "models/map_objects/imp_mine/turret_canon.glm"
00020 #define name2 "models/map_objects/imp_mine/turret_damage.md3"
00021 #define name3 "models/map_objects/wedge/laser_cannon_model.glm"
00022
00023
00024 void G2Tur_SetBoneAngles(gentity_t *ent, char *bone, vec3_t angles)
00025 {
00026 #ifdef _XBOX
00027 byte *thebone = &ent->s.boneIndex1;
00028 byte *firstFree = NULL;
00029 #else
00030 int *thebone = &ent->s.boneIndex1;
00031 int *firstFree = NULL;
00032 #endif
00033 int i = 0;
00034 int boneIndex = G_BoneIndex(bone);
00035 int flags, up, right, forward;
00036 vec3_t *boneVector = &ent->s.boneAngles1;
00037 vec3_t *freeBoneVec = NULL;
00038
00039 while (thebone)
00040 {
00041 if (!*thebone && !firstFree)
00042 {
00043 firstFree = thebone;
00044 freeBoneVec = boneVector;
00045 }
00046 else if (*thebone)
00047 {
00048 if (*thebone == boneIndex)
00049 {
00050 break;
00051 }
00052 }
00053
00054 switch (i)
00055 {
00056 case 0:
00057 thebone = &ent->s.boneIndex2;
00058 boneVector = &ent->s.boneAngles2;
00059 break;
00060 case 1:
00061 thebone = &ent->s.boneIndex3;
00062 boneVector = &ent->s.boneAngles3;
00063 break;
00064 case 2:
00065 thebone = &ent->s.boneIndex4;
00066 boneVector = &ent->s.boneAngles4;
00067 break;
00068 default:
00069 thebone = NULL;
00070 boneVector = NULL;
00071 break;
00072 }
00073
00074 i++;
00075 }
00076
00077 if (!thebone)
00078 {
00079 if (!firstFree)
00080 {
00081 Com_Printf("WARNING: NPC has no free bone indexes\n");
00082 return;
00083 }
00084
00085 thebone = firstFree;
00086
00087 *thebone = boneIndex;
00088 boneVector = freeBoneVec;
00089 }
00090
00091
00092
00093
00094
00095 VectorCopy(angles, *boneVector);
00096
00097
00098
00099 if (!ent->ghoul2)
00100 {
00101 return;
00102 }
00103
00104 flags = BONE_ANGLES_POSTMULT;
00105 up = POSITIVE_Y;
00106 right = NEGATIVE_Z;
00107 forward = NEGATIVE_X;
00108
00109
00110 ent->s.boneOrient = ((forward)|(right<<3)|(up<<6));
00111
00112 trap_G2API_SetBoneAngles( ent->ghoul2,
00113 0,
00114 bone,
00115 angles,
00116 flags,
00117 up,
00118 right,
00119 forward,
00120 NULL,
00121 100,
00122 level.time );
00123 }
00124
00125 void turretG2_set_models( gentity_t *self, qboolean dying )
00126 {
00127 if ( dying )
00128 {
00129 if ( !(self->spawnflags&SPF_TURRETG2_TURBO) )
00130 {
00131 self->s.modelindex = G_ModelIndex( name2 );
00132 self->s.modelindex2 = G_ModelIndex( name );
00133 }
00134
00135 trap_G2API_RemoveGhoul2Model( &self->ghoul2, 0 );
00136 G_KillG2Queue( self->s.number );
00137 self->s.modelGhoul2 = 0;
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 }
00151 else
00152 {
00153 if ( !(self->spawnflags&SPF_TURRETG2_TURBO) )
00154 {
00155 self->s.modelindex = G_ModelIndex( name );
00156 self->s.modelindex2 = G_ModelIndex( name2 );
00157
00158 trap_G2API_InitGhoul2Model( &self->ghoul2,
00159 name,
00160 0,
00161
00162
00163
00164 0,
00165 0,
00166 0,
00167 0);
00168 }
00169 else
00170 {
00171 self->s.modelindex = G_ModelIndex( name3 );
00172
00173 trap_G2API_InitGhoul2Model( &self->ghoul2,
00174 name3,
00175 0,
00176
00177
00178
00179 0,
00180 0,
00181 0,
00182 0);
00183 }
00184
00185 self->s.modelGhoul2 = 1;
00186 if ( (self->spawnflags&SPF_TURRETG2_TURBO) )
00187 {
00188 self->s.g2radius = 128;
00189 }
00190 else
00191 {
00192 self->s.g2radius = 80;
00193 }
00194
00195 if ( (self->spawnflags&SPF_TURRETG2_TURBO) )
00196 {
00197 G2Tur_SetBoneAngles(self, "pitch", vec3_origin);
00198 self->genericValue11 = trap_G2API_AddBolt( self->ghoul2, 0, "*muzzle1" );
00199 self->genericValue12 = trap_G2API_AddBolt( self->ghoul2, 0, "*muzzle2" );
00200 }
00201 else
00202 {
00203 G2Tur_SetBoneAngles(self, "Bone_body", vec3_origin);
00204 self->genericValue11 = trap_G2API_AddBolt( self->ghoul2, 0, "*flash03" );
00205 }
00206 }
00207 }
00208
00209
00210 void TurretG2Pain( gentity_t *self, gentity_t *attacker, int damage )
00211
00212 {
00213 if (self->paintarget && self->paintarget[0])
00214 {
00215 if (self->genericValue8 < level.time)
00216 {
00217 G_UseTargets2(self, self, self->paintarget);
00218 self->genericValue8 = level.time + self->genericValue4;
00219 }
00220 }
00221
00222 if ( attacker->client && attacker->client->ps.weapon == WP_DEMP2 )
00223 {
00224 self->attackDebounceTime = level.time + 2000 + random() * 500;
00225 self->painDebounceTime = self->attackDebounceTime;
00226 }
00227 if ( !self->enemy )
00228 {
00229 G_SetEnemy( self, attacker );
00230 }
00231
00232
00233 }
00234
00235
00236 void turretG2_die ( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath )
00237
00238 {
00239 vec3_t forward = { 0,0,-1 }, pos;
00240
00241
00242
00243 self->use = NULL;
00244
00245
00246 self->die = NULL;
00247 self->pain = NULL;
00248 self->takedamage = qfalse;
00249 self->s.health = self->health = 0;
00250 self->s.loopSound = 0;
00251 self->s.shouldtarget = qfalse;
00252
00253
00254
00255 if ( self->spawnflags & 2 )
00256 {
00257 VectorSet( forward, 0, 0, 1 );
00258 }
00259
00260
00261
00262 VectorMA( self->r.currentOrigin, 12, forward, pos );
00263 G_PlayEffect( EFFECT_EXPLOSION_TURRET, pos, forward );
00264
00265 if ( self->splashDamage > 0 && self->splashRadius > 0 )
00266 {
00267 G_RadiusDamage( self->r.currentOrigin,
00268 attacker,
00269 self->splashDamage,
00270 self->splashRadius,
00271 attacker,
00272 NULL,
00273 MOD_UNKNOWN );
00274 }
00275
00276 if ( self->s.eFlags & EF_SHADER_ANIM )
00277 {
00278 self->s.frame = 1;
00279 }
00280
00281 self->s.weapon = 0;
00282
00283 if ( self->s.modelindex2 )
00284 {
00285
00286 turretG2_set_models( self, qtrue );
00287
00288 VectorCopy( self->r.currentAngles, self->s.apos.trBase );
00289 VectorClear( self->s.apos.trDelta );
00290
00291 if ( self->target )
00292 {
00293 G_UseTargets( self, attacker );
00294 }
00295
00296 if (self->spawnflags & SPF_TURRETG2_CANRESPAWN)
00297 {
00298 if (self->health < 1 && !self->genericValue5)
00299 {
00300 self->genericValue5 = level.time + self->count;
00301 }
00302 }
00303 }
00304 else
00305 {
00306 ObjectDie( self, inflictor, attacker, damage, meansOfDeath );
00307 }
00308 }
00309
00310 #define START_DIS 15
00311
00312
00313 void TurboLaser_SetBoneAnim(gentity_t *eweb, int startFrame, int endFrame)
00314 {
00315
00316 eweb->s.eFlags |= EF_G2ANIMATING;
00317
00318 if (eweb->s.torsoAnim == startFrame && eweb->s.legsAnim == endFrame)
00319 {
00320 eweb->s.torsoFlip = !eweb->s.torsoFlip;
00321 }
00322 else
00323 {
00324 eweb->s.torsoAnim = startFrame;
00325 eweb->s.legsAnim = endFrame;
00326 }
00327
00328
00329 assert(eweb->ghoul2);
00330 trap_G2API_SetBoneAnim(eweb->ghoul2, 0, "model_root", startFrame, endFrame,
00331 (BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND), 1.0f, level.time, -1, 100);
00332 }
00333
00334 extern void WP_FireTurboLaserMissile( gentity_t *ent, vec3_t start, vec3_t dir );
00335
00336 static void turretG2_fire ( gentity_t *ent, vec3_t start, vec3_t dir )
00337
00338 {
00339 vec3_t org, ang;
00340 gentity_t *bolt;
00341
00342 if ( (trap_PointContents( start, ent->s.number )&MASK_SHOT) )
00343 {
00344 return;
00345 }
00346
00347 VectorMA( start, -START_DIS, dir, org );
00348
00349 if ( ent->random )
00350 {
00351 vectoangles( dir, ang );
00352 ang[PITCH] += flrand( -ent->random, ent->random );
00353 ang[YAW] += flrand( -ent->random, ent->random );
00354 AngleVectors( ang, dir, NULL, NULL );
00355 }
00356
00357 vectoangles(dir, ang);
00358
00359 if ( (ent->spawnflags&SPF_TURRETG2_TURBO) )
00360 {
00361
00362 G_PlayEffectID( ent->genericValue13, org, ang );
00363 WP_FireTurboLaserMissile( ent, start, dir );
00364 if ( ent->alt_fire )
00365 {
00366 TurboLaser_SetBoneAnim( ent, 2, 3 );
00367 }
00368 else
00369 {
00370 TurboLaser_SetBoneAnim( ent, 0, 1 );
00371 }
00372 }
00373 else
00374 {
00375 G_PlayEffectID( G_EffectIndex("blaster/muzzle_flash"), org, ang );
00376 bolt = G_Spawn();
00377
00378 bolt->classname = "turret_proj";
00379 bolt->nextthink = level.time + 10000;
00380 bolt->think = G_FreeEntity;
00381 bolt->s.eType = ET_MISSILE;
00382 bolt->s.weapon = WP_BLASTER;
00383 bolt->r.ownerNum = ent->s.number;
00384 bolt->damage = ent->damage;
00385 bolt->alliedTeam = ent->alliedTeam;
00386 bolt->teamnodmg = ent->teamnodmg;
00387 bolt->dflags = (DAMAGE_NO_KNOCKBACK|DAMAGE_HEAVY_WEAP_CLASS);
00388 bolt->splashDamage = ent->splashDamage;
00389 bolt->splashRadius = ent->splashDamage;
00390 bolt->methodOfDeath = MOD_TARGET_LASER;
00391 bolt->splashMethodOfDeath = MOD_TARGET_LASER;
00392 bolt->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00393
00394
00395 VectorSet( bolt->r.maxs, 1.5, 1.5, 1.5 );
00396 VectorScale( bolt->r.maxs, -1, bolt->r.mins );
00397 bolt->s.pos.trType = TR_LINEAR;
00398 bolt->s.pos.trTime = level.time;
00399 VectorCopy( start, bolt->s.pos.trBase );
00400 VectorScale( dir, ent->mass, bolt->s.pos.trDelta );
00401 SnapVector( bolt->s.pos.trDelta );
00402 VectorCopy( start, bolt->r.currentOrigin);
00403 }
00404 }
00405
00406 void turretG2_respawn( gentity_t *self )
00407 {
00408 self->use = turretG2_base_use;
00409 self->pain = TurretG2Pain;
00410 self->die = turretG2_die;
00411 self->takedamage = qtrue;
00412 self->s.shouldtarget = qtrue;
00413
00414 if ( self->s.eFlags & EF_SHADER_ANIM )
00415 {
00416 self->s.frame = 0;
00417 }
00418 self->s.weapon = WP_TURRET;
00419
00420 turretG2_set_models( self, qfalse );
00421 self->s.health = self->health = self->genericValue6;
00422 if (self->maxHealth) {
00423 G_ScaleNetHealth(self);
00424 }
00425 self->genericValue5 = 0;
00426 }
00427
00428
00429 void turretG2_head_think( gentity_t *self )
00430
00431 {
00432
00433 if ( self->enemy
00434 && self->setTime < level.time
00435 && self->attackDebounceTime < level.time )
00436 {
00437 vec3_t fwd, org;
00438 mdxaBone_t boltMatrix;
00439
00440
00441 self->setTime = level.time + self->wait;
00442
00443
00444 trap_G2API_GetBoltMatrix( self->ghoul2,
00445 0,
00446 (self->alt_fire?self->genericValue12:self->genericValue11),
00447 &boltMatrix,
00448 self->r.currentAngles,
00449 self->r.currentOrigin,
00450 level.time,
00451 NULL,
00452 self->modelScale );
00453 if ( (self->spawnflags&SPF_TURRETG2_TURBO) )
00454 {
00455 self->alt_fire = !self->alt_fire;
00456 }
00457
00458 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, org );
00459
00460 if ( (self->spawnflags&SPF_TURRETG2_TURBO) )
00461 {
00462 BG_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, fwd );
00463 }
00464 else
00465 {
00466 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_X, fwd );
00467 }
00468
00469 VectorMA( org, START_DIS, fwd, org );
00470
00471 turretG2_fire( self, org, fwd );
00472 self->fly_sound_debounce_time = level.time;
00473 }
00474 }
00475
00476
00477 static void turretG2_aim( gentity_t *self )
00478
00479 {
00480 vec3_t enemyDir, org, org2;
00481 vec3_t desiredAngles, setAngle;
00482 float diffYaw = 0.0f, diffPitch = 0.0f;
00483 float maxYawSpeed = (self->spawnflags&SPF_TURRETG2_TURBO)?30.0f:14.0f;
00484 float maxPitchSpeed = (self->spawnflags&SPF_TURRETG2_TURBO)?15.0f:3.0f;
00485
00486
00487 BG_EvaluateTrajectory( &self->s.apos, level.time, self->r.currentAngles );
00488 self->r.currentAngles[YAW] = AngleNormalize360( self->r.currentAngles[YAW] );
00489 self->speed = AngleNormalize360( self->speed );
00490
00491 if ( self->enemy )
00492 {
00493 mdxaBone_t boltMatrix;
00494
00495
00496 if ( self->enemy->client )
00497 {
00498 VectorCopy( self->enemy->client->renderInfo.eyePoint, org );
00499 }
00500 else
00501 {
00502 VectorCopy( self->enemy->r.currentOrigin, org );
00503 }
00504 if ( self->spawnflags & 2 )
00505 {
00506 org[2] -= 15;
00507 }
00508 else
00509 {
00510 org[2] -= 5;
00511 }
00512
00513 if ( (self->spawnflags&SPF_TURRETG2_LEAD_ENEMY) )
00514 {
00515 vec3_t diff, velocity;
00516 float dist;
00517 VectorSubtract( org, self->s.origin, diff );
00518 dist = VectorNormalize( diff );
00519 if ( self->enemy->client )
00520 {
00521 VectorCopy( self->enemy->client->ps.velocity, velocity );
00522 }
00523 else
00524 {
00525 VectorCopy( self->enemy->s.pos.trDelta, velocity );
00526 }
00527 VectorMA( org, (dist/self->mass), velocity, org );
00528 }
00529
00530
00531 trap_G2API_GetBoltMatrix( self->ghoul2,
00532 0,
00533 (self->alt_fire?self->genericValue12:self->genericValue11),
00534 &boltMatrix,
00535 self->r.currentAngles,
00536 self->s.origin,
00537 level.time,
00538 NULL,
00539 self->modelScale );
00540
00541 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, org2 );
00542
00543 VectorSubtract( org, org2, enemyDir );
00544 vectoangles( enemyDir, desiredAngles );
00545
00546 diffYaw = AngleSubtract( self->r.currentAngles[YAW], desiredAngles[YAW] );
00547 diffPitch = AngleSubtract( self->speed, desiredAngles[PITCH] );
00548 }
00549 else
00550 {
00551
00552
00553 }
00554
00555 if ( diffYaw )
00556 {
00557
00558 if ( fabs(diffYaw) > maxYawSpeed )
00559 {
00560 diffYaw = ( diffYaw >= 0 ? maxYawSpeed : -maxYawSpeed );
00561 }
00562
00563
00564 VectorSet( setAngle, 0.0f, diffYaw, 0.0f );
00565
00566 VectorCopy( self->r.currentAngles, self->s.apos.trBase );
00567 VectorScale( setAngle,- 5, self->s.apos.trDelta );
00568 self->s.apos.trTime = level.time;
00569 self->s.apos.trType = TR_LINEAR;
00570 }
00571
00572 if ( diffPitch )
00573 {
00574 if ( fabs(diffPitch) > maxPitchSpeed )
00575 {
00576
00577 self->speed += (diffPitch > 0.0f) ? -maxPitchSpeed : maxPitchSpeed;
00578 }
00579 else
00580 {
00581
00582 self->speed -= ( diffPitch );
00583 }
00584
00585
00586 if ( (self->spawnflags&SPF_TURRETG2_TURBO) )
00587 {
00588 if ( self->spawnflags & 2 )
00589 {
00590 VectorSet( desiredAngles, 0.0f, 0.0f, -self->speed );
00591 }
00592 else
00593 {
00594 VectorSet( desiredAngles, 0.0f, 0.0f, self->speed );
00595 }
00596 G2Tur_SetBoneAngles(self, "pitch", desiredAngles);
00597 }
00598 else
00599 {
00600 if ( self->spawnflags & 2 )
00601 {
00602 VectorSet( desiredAngles, self->speed, 0.0f, 0.0f );
00603 }
00604 else
00605 {
00606 VectorSet( desiredAngles, -self->speed, 0.0f, 0.0f );
00607 }
00608 G2Tur_SetBoneAngles(self, "Bone_body", desiredAngles);
00609 }
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 }
00624
00625 if ( diffYaw || diffPitch )
00626 {
00627 if ( (self->spawnflags&SPF_TURRETG2_TURBO) )
00628 {
00629 self->s.loopSound = G_SoundIndex( "sound/vehicles/weapons/turbolaser/turn.wav" );
00630 }
00631 else
00632 {
00633 self->s.loopSound = G_SoundIndex( "sound/chars/turret/move.wav" );
00634 }
00635 }
00636 else
00637 {
00638 self->s.loopSound = 0;
00639 }
00640 }
00641
00642
00643 static void turretG2_turnoff( gentity_t *self )
00644
00645 {
00646 if ( self->enemy == NULL )
00647 {
00648
00649 return;
00650 }
00651 if ( (self->spawnflags&SPF_TURRETG2_TURBO) )
00652 {
00653 TurboLaser_SetBoneAnim( self, 4, 5 );
00654 }
00655
00656 if ( !(self->spawnflags&SPF_TURRETG2_TURBO) )
00657 {
00658 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/chars/turret/shutdown.wav" ));
00659 }
00660
00661
00662 self->aimDebounceTime = level.time + 5000;
00663
00664
00665 self->enemy = NULL;
00666 }
00667
00668
00669 static qboolean turretG2_find_enemies( gentity_t *self )
00670
00671 {
00672 qboolean found = qfalse;
00673 int i, count;
00674 float bestDist = self->radius * self->radius;
00675 float enemyDist;
00676 vec3_t enemyDir, org, org2;
00677 qboolean foundClient = qfalse;
00678 gentity_t *entity_list[MAX_GENTITIES], *target, *bestTarget = NULL;
00679
00680 if ( self->aimDebounceTime > level.time )
00681 {
00682
00683 if ( self->painDebounceTime < level.time )
00684 {
00685 if ( !(self->spawnflags&SPF_TURRETG2_TURBO) )
00686 {
00687 G_Sound(self, CHAN_BODY, G_SoundIndex( "sound/chars/turret/ping.wav" ));
00688 }
00689 self->painDebounceTime = level.time + 1000;
00690 }
00691 }
00692
00693 VectorCopy( self->r.currentOrigin, org2 );
00694 if ( self->spawnflags & 2 )
00695 {
00696 org2[2] += 20;
00697 }
00698 else
00699 {
00700 org2[2] -= 20;
00701 }
00702
00703 count = G_RadiusList( org2, self->radius, self, qtrue, entity_list );
00704
00705 for ( i = 0; i < count; i++ )
00706 {
00707 trace_t tr;
00708 target = entity_list[i];
00709
00710 if ( !target->client )
00711 {
00712
00713 if ( !(target->flags&FL_BBRUSH)
00714 || !target->takedamage
00715 || (target->NPC_targetname&&self->targetname&&Q_stricmp(target->NPC_targetname,self->targetname)!=0) )
00716 {
00717 continue;
00718 }
00719
00720 }
00721 if ( target == self || !target->takedamage || target->health <= 0 || ( target->flags & FL_NOTARGET ))
00722 {
00723 continue;
00724 }
00725 if ( target->client && target->client->sess.sessionTeam == TEAM_SPECTATOR )
00726 {
00727 continue;
00728 }
00729 if ( self->alliedTeam )
00730 {
00731 if ( target->client )
00732 {
00733 if ( target->client->sess.sessionTeam == self->alliedTeam )
00734 {
00735
00736 continue;
00737 }
00738 }
00739 else if ( target->teamnodmg == self->alliedTeam )
00740 {
00741
00742 continue;
00743 }
00744 }
00745 if ( !trap_InPVS( org2, target->r.currentOrigin ))
00746 {
00747 continue;
00748 }
00749
00750 if ( target->client )
00751 {
00752 VectorCopy( target->client->renderInfo.eyePoint, org );
00753 }
00754 else
00755 {
00756 VectorCopy( target->r.currentOrigin, org );
00757 }
00758
00759 if ( self->spawnflags & 2 )
00760 {
00761 org[2] -= 15;
00762 }
00763 else
00764 {
00765 org[2] += 5;
00766 }
00767
00768 trap_Trace( &tr, org2, NULL, NULL, org, self->s.number, MASK_SHOT );
00769
00770 if ( !tr.allsolid && !tr.startsolid && ( tr.fraction == 1.0 || tr.entityNum == target->s.number ))
00771 {
00772
00773 VectorSubtract( target->r.currentOrigin, self->r.currentOrigin, enemyDir );
00774 enemyDist = VectorLengthSquared( enemyDir );
00775
00776 if ( enemyDist < bestDist || (target->client && !foundClient))
00777 {
00778 if ( self->attackDebounceTime < level.time )
00779 {
00780
00781 if ( !(self->spawnflags&SPF_TURRETG2_TURBO) )
00782 {
00783 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/chars/turret/startup.wav" ));
00784 }
00785
00786
00787 self->attackDebounceTime = level.time + 1400;
00788 }
00789
00790 bestTarget = target;
00791 bestDist = enemyDist;
00792 found = qtrue;
00793 if ( target->client )
00794 {
00795 foundClient = qtrue;
00796 }
00797 }
00798 }
00799 }
00800
00801 if ( found )
00802 {
00803
00804
00805
00806
00807
00808
00809
00810 G_SetEnemy( self, bestTarget );
00811 if ( VALIDSTRING( self->target2 ))
00812 {
00813 G_UseTargets2( self, self, self->target2 );
00814 }
00815 }
00816
00817 return found;
00818 }
00819
00820
00821 void turretG2_base_think( gentity_t *self )
00822
00823 {
00824 qboolean turnOff = qtrue;
00825 float enemyDist;
00826 vec3_t enemyDir, org, org2;
00827
00828 self->nextthink = level.time + FRAMETIME;
00829
00830 if ( self->health <= 0 )
00831 {
00832 if (self->spawnflags & SPF_TURRETG2_CANRESPAWN)
00833 {
00834 if ( self->genericValue5 && self->genericValue5 < level.time )
00835 {
00836 turretG2_respawn( self );
00837 }
00838 }
00839 return;
00840 }
00841 else if ( self->spawnflags & 1 )
00842 {
00843 turretG2_turnoff( self );
00844 turretG2_aim( self );
00845
00846
00847 self->flags |= FL_NOTARGET;
00848 return;
00849 }
00850 else
00851 {
00852
00853 self->flags &= ~FL_NOTARGET;
00854 }
00855
00856 if ( self->enemy )
00857 {
00858 if ( self->enemy->health < 0
00859 || !self->enemy->inuse )
00860 {
00861 self->enemy = NULL;
00862 }
00863 }
00864
00865 if ( self->last_move_time < level.time )
00866 {
00867 if ( turretG2_find_enemies( self ) )
00868 {
00869 turnOff = qfalse;
00870 if ( self->enemy->client )
00871 {
00872 self->last_move_time = level.time + 3000;
00873 }
00874 else
00875 {
00876 self->last_move_time = level.time + 500;
00877 }
00878 }
00879 }
00880
00881 if ( self->enemy != NULL )
00882 {
00883 if ( self->enemy->client && self->enemy->client->sess.sessionTeam == TEAM_SPECTATOR )
00884 {
00885 self->enemy = NULL;
00886 }
00887 else
00888 {
00889
00890 VectorSubtract( self->enemy->r.currentOrigin, self->r.currentOrigin, enemyDir );
00891 enemyDist = VectorLengthSquared( enemyDir );
00892
00893 if ( enemyDist < self->radius * self->radius )
00894 {
00895
00896 if ( trap_InPVS( self->r.currentOrigin, self->enemy->r.currentOrigin ) )
00897 {
00898
00899 trace_t tr;
00900
00901 if ( self->enemy->client )
00902 {
00903 VectorCopy( self->enemy->client->renderInfo.eyePoint, org );
00904 }
00905 else
00906 {
00907 VectorCopy( self->enemy->r.currentOrigin, org );
00908 }
00909 VectorCopy( self->r.currentOrigin, org2 );
00910 if ( self->spawnflags & 2 )
00911 {
00912 org2[2] += 10;
00913 }
00914 else
00915 {
00916 org2[2] -= 10;
00917 }
00918 trap_Trace( &tr, org2, NULL, NULL, org, self->s.number, MASK_SHOT );
00919
00920 if ( !tr.allsolid && !tr.startsolid && tr.entityNum == self->enemy->s.number )
00921 {
00922 turnOff = qfalse;
00923 }
00924 }
00925 }
00926
00927 }
00928 }
00929
00930 if ( turnOff )
00931 {
00932 if ( self->bounceCount < level.time )
00933 {
00934 turretG2_turnoff( self );
00935 }
00936 }
00937 else
00938 {
00939
00940 self->bounceCount = level.time + 2000 + random() * 150;
00941 }
00942
00943 turretG2_aim( self );
00944 if ( !turnOff )
00945 {
00946 turretG2_head_think( self );
00947 }
00948 }
00949
00950
00951 void turretG2_base_use( gentity_t *self, gentity_t *other, gentity_t *activator )
00952
00953 {
00954
00955 self->spawnflags = (self->spawnflags ^ 1);
00956
00957 if (( self->s.eFlags & EF_SHADER_ANIM ) && ( self->spawnflags & 1 ))
00958 {
00959 self->s.frame = 1;
00960 }
00961 else
00962 {
00963 self->s.frame = 0;
00964 }
00965 }
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 void SP_misc_turretG2( gentity_t *base )
01022
01023 {
01024 int customscaleVal;
01025 char* s;
01026
01027 turretG2_set_models( base, qfalse );
01028
01029 G_SpawnInt("painwait", "0", &base->genericValue4);
01030 base->genericValue8 = 0;
01031
01032 G_SpawnInt("customscale", "0", &customscaleVal);
01033 base->s.iModelScale = customscaleVal;
01034 if (base->s.iModelScale)
01035 {
01036 if (base->s.iModelScale > 1023)
01037 {
01038 base->s.iModelScale = 1023;
01039 }
01040 base->modelScale[0] = base->modelScale[1] = base->modelScale[2] = base->s.iModelScale/100.0f;
01041 }
01042
01043 G_SpawnString( "icon", "", &s );
01044 if (s && s[0])
01045 {
01046
01047
01048 base->s.genericenemyindex = G_IconIndex(s);
01049 }
01050
01051 finish_spawning_turretG2( base );
01052
01053 if (( base->spawnflags & 1 ))
01054 {
01055 base->s.frame = 1;
01056 }
01057 else
01058 {
01059 base->s.frame = 0;
01060 }
01061 if ( !(base->spawnflags&SPF_TURRETG2_TURBO) )
01062 {
01063 base->s.eFlags |= EF_SHADER_ANIM;
01064 }
01065
01066 if (base->spawnflags & SPF_SHOWONRADAR)
01067 {
01068 base->s.eFlags |= EF_RADAROBJECT;
01069 }
01070 #undef name
01071 #undef name2
01072 #undef name3
01073 }
01074
01075
01076 void finish_spawning_turretG2( gentity_t *base )
01077 {
01078 vec3_t fwd;
01079 int t;
01080
01081 if ( (base->spawnflags&2) )
01082 {
01083 base->s.angles[ROLL] += 180;
01084 base->s.origin[2] -= 22.0f;
01085 }
01086
01087 G_SetAngles( base, base->s.angles );
01088 AngleVectors( base->r.currentAngles, fwd, NULL, NULL );
01089
01090 G_SetOrigin(base, base->s.origin);
01091
01092 base->s.eType = ET_GENERAL;
01093
01094 if ( base->team && base->team[0] &&
01095 !base->teamnodmg)
01096 {
01097 base->teamnodmg = atoi(base->team);
01098 }
01099 base->team = NULL;
01100
01101
01102 G_EffectIndex( "turret/explode" );
01103 G_EffectIndex( "sparks/spark_exp_nosnd" );
01104
01105 base->use = turretG2_base_use;
01106 base->pain = TurretG2Pain;
01107
01108
01109 base->think = turretG2_base_think;
01110 base->nextthink = level.time + FRAMETIME * 5;
01111
01112
01113 base->speed = 0;
01114
01115
01116 if ( (base->spawnflags&SPF_TURRETG2_CANRESPAWN) && !base->count )
01117 {
01118 base->count = 20000;
01119 }
01120
01121 G_SpawnFloat( "shotspeed", "0", &base->mass );
01122 if ( (base->spawnflags&SPF_TURRETG2_TURBO) )
01123 {
01124 if ( !base->random )
01125 {
01126 base->random = 2.0f;
01127 }
01128
01129 if ( !base->mass )
01130 {
01131 base->mass = 20000;
01132 }
01133
01134 if ( !base->health )
01135 {
01136 base->health = 2000;
01137 }
01138
01139
01140 if ( !base->radius )
01141 {
01142 base->radius = 32768;
01143 }
01144
01145
01146 if ( !base->wait )
01147 {
01148 base->wait = 1000;
01149 }
01150
01151 if ( !base->splashDamage )
01152 {
01153 base->splashDamage = 200;
01154 }
01155
01156 if ( !base->splashRadius )
01157 {
01158 base->splashRadius = 500;
01159 }
01160
01161
01162 if ( !base->damage )
01163 {
01164 base->damage = 500;
01165 }
01166
01167 if ( (base->spawnflags&SPF_TURRETG2_TURBO) )
01168 {
01169 VectorSet( base->r.maxs, 64.0f, 64.0f, 30.0f );
01170 VectorSet( base->r.mins, -64.0f, -64.0f, -30.0f );
01171 }
01172
01173 TurboLaser_SetBoneAnim( base, 4, 5 );
01174 if ( g_gametype.integer == GT_SIEGE )
01175 {
01176
01177 base->s.eFlags2 |= EF2_BRACKET_ENTITY;
01178 }
01179 }
01180 else
01181 {
01182 if ( !base->random )
01183 {
01184 base->random = 2.0f;
01185 }
01186
01187 if ( !base->mass )
01188 {
01189 base->mass = 1100;
01190 }
01191
01192 if ( !base->health )
01193 {
01194 base->health = 100;
01195 }
01196
01197
01198 if ( !base->radius )
01199 {
01200 base->radius = 512;
01201 }
01202
01203
01204 if ( !base->wait )
01205 {
01206 base->wait = 150 + random() * 55;
01207 }
01208
01209 if ( !base->splashDamage )
01210 {
01211 base->splashDamage = 10;
01212 }
01213
01214 if ( !base->splashRadius )
01215 {
01216 base->splashRadius = 25;
01217 }
01218
01219
01220 if ( !base->damage )
01221 {
01222 base->damage = 5;
01223 }
01224
01225 if ( base->spawnflags & 2 )
01226 {
01227 VectorSet( base->r.maxs, 10.0f, 10.0f, 30.0f );
01228 VectorSet( base->r.mins, -10.0f, -10.0f, 0.0f );
01229 }
01230 else
01231 {
01232 VectorSet( base->r.maxs, 10.0f, 10.0f, 0.0f );
01233 VectorSet( base->r.mins, -10.0f, -10.0f, -30.0f );
01234 }
01235 }
01236
01237
01238 base->genericValue6 = base->health;
01239
01240 G_SpawnInt( "showhealth", "0", &t );
01241 if (t)
01242 {
01243 base->maxHealth = base->health;
01244 G_ScaleNetHealth(base);
01245 base->s.shouldtarget = qtrue;
01246
01247 }
01248
01249 if (base->s.iModelScale)
01250 {
01251 float fScale = base->s.iModelScale/100.0f;
01252 VectorScale(base->r.mins, fScale, base->r.mins);
01253 VectorScale(base->r.maxs, fScale, base->r.maxs);
01254 }
01255
01256
01257 if ( (base->spawnflags&SPF_TURRETG2_TURBO) )
01258 {
01259 base->genericValue13 = G_EffectIndex( "turret/turb_muzzle_flash" );
01260 base->genericValue14 = G_EffectIndex( "turret/turb_shot" );
01261 base->genericValue15 = G_EffectIndex( "turret/turb_impact" );
01262
01263 G_SoundIndex( "sound/vehicles/weapons/turbolaser/turn.wav" );
01264 }
01265 else
01266 {
01267 G_SoundIndex( "sound/chars/turret/startup.wav" );
01268 G_SoundIndex( "sound/chars/turret/shutdown.wav" );
01269 G_SoundIndex( "sound/chars/turret/ping.wav" );
01270 G_SoundIndex( "sound/chars/turret/move.wav" );
01271 }
01272
01273 base->r.contents = CONTENTS_BODY|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_SHOTCLIP;
01274
01275
01276 base->takedamage = qtrue;
01277 base->die = turretG2_die;
01278
01279 base->material = MAT_METAL;
01280