codemp/game/NPC_AI_Atst.c

Go to the documentation of this file.
00001 #include "b_local.h"
00002 
00003 #define MIN_MELEE_RANGE         640
00004 #define MIN_MELEE_RANGE_SQR     ( MIN_MELEE_RANGE * MIN_MELEE_RANGE )
00005 
00006 #define MIN_DISTANCE            128
00007 #define MIN_DISTANCE_SQR        ( MIN_DISTANCE * MIN_DISTANCE )
00008 
00009 #define TURN_OFF                        0x00000100//G2SURFACEFLAG_NODESCENDANTS
00010 
00011 #define LEFT_ARM_HEALTH 40
00012 #define RIGHT_ARM_HEALTH 40
00013 
00014 extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath );
00015 /*
00016 -------------------------
00017 NPC_ATST_Precache
00018 -------------------------
00019 */
00020 void NPC_ATST_Precache(void)
00021 {
00022         G_SoundIndex( "sound/chars/atst/atst_damaged1" );
00023         G_SoundIndex( "sound/chars/atst/atst_damaged2" );
00024 
00025 //      RegisterItem( BG_FindItemForWeapon( WP_ATST_MAIN ));    //precache the weapon
00026         //rwwFIXMEFIXME: add this weapon
00027         RegisterItem( BG_FindItemForWeapon( WP_BOWCASTER ));    //precache the weapon
00028         RegisterItem( BG_FindItemForWeapon( WP_ROCKET_LAUNCHER ));      //precache the weapon
00029 
00030         G_EffectIndex( "env/med_explode2" );
00031 //      G_EffectIndex( "smaller_chunks" );
00032         G_EffectIndex( "blaster/smoke_bolton" );
00033         G_EffectIndex( "explosions/droidexplosion1" );
00034 }
00035 
00036 //-----------------------------------------------------------------
00037 #if 0
00038 static void ATST_PlayEffect( gentity_t *self, const int boltID, const char *fx )
00039 {
00040         if ( boltID >=0 && fx && fx[0] )
00041         {
00042                 mdxaBone_t      boltMatrix;
00043                 vec3_t          org, dir;
00044 
00045                 trap_G2API_GetBoltMatrix( self->ghoul2, 0, 
00046                                         boltID,
00047                                         &boltMatrix, self->r.currentAngles, self->r.currentOrigin, level.time,
00048                                         NULL, self->modelScale );
00049 
00050                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, org );
00051                 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, dir );
00052 
00053                 G_PlayEffectID( G_EffectIndex((char *)fx), org, dir );
00054         }
00055 }
00056 #endif
00057 
00058 /*
00059 -------------------------
00060 G_ATSTCheckPain
00061 
00062 Called by NPC's and player in an ATST
00063 -------------------------
00064 */
00065 
00066 void G_ATSTCheckPain( gentity_t *self, gentity_t *other, int damage )
00067 {
00068         //int newBolt;
00069         //int hitLoc = gPainHitLoc;
00070         
00071         if ( rand() & 1 )
00072         {
00073                 G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/atst/atst_damaged1" );
00074         }
00075         else
00076         {
00077                 G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/atst/atst_damaged2" );
00078         }
00079 
00080         /*
00081         if ((hitLoc==HL_ARM_LT) && (self->locationDamage[HL_ARM_LT] > LEFT_ARM_HEALTH))
00082         {
00083                 if (self->locationDamage[hitLoc] >= LEFT_ARM_HEALTH)    // Blow it up?
00084                 {
00085                         newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*flash3" );
00086                         if ( newBolt != -1 )
00087                         {
00088 //                              G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt1, self->s.number);
00089                                 ATST_PlayEffect( self, trap_G2API_AddBolt(self->ghoul2, 0, "*flash3"), "env/med_explode2" );
00090                                 //G_PlayEffectID( G_EffectIndex("blaster/smoke_bolton"), self->playerModel, newBolt, self->s.number);
00091                                 //Maybe bother with this some other time.
00092                         }
00093 
00094                         NPC_SetSurfaceOnOff( self, "head_light_blaster_cann", TURN_OFF );
00095                 }
00096         }
00097         else if ((hitLoc==HL_ARM_RT) && (self->locationDamage[HL_ARM_RT] > RIGHT_ARM_HEALTH))   // Blow it up?
00098         {
00099                 if (self->locationDamage[hitLoc] >= RIGHT_ARM_HEALTH)
00100                 {                       
00101                         newBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*flash4" );
00102                         if ( newBolt != -1 )
00103                         {
00104 //                              G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt2, self->s.number);
00105                                 ATST_PlayEffect( self, trap_G2API_AddBolt(self->ghoul2, 0, "*flash4"), "env/med_explode2" );
00106                                 //G_PlayEffect( "blaster/smoke_bolton", self->playerModel, newBolt, self->s.number);
00107                         }
00108 
00109                         NPC_SetSurfaceOnOff( self, "head_concussion_charger", TURN_OFF );
00110                 }
00111         }
00112         */
00113 }
00114 /*
00115 -------------------------
00116 NPC_ATST_Pain
00117 -------------------------
00118 */
00119 void NPC_ATST_Pain(gentity_t *self, gentity_t *attacker, int damage) 
00120 {
00121         G_ATSTCheckPain( self, attacker, damage );
00122         NPC_Pain( self, attacker, damage );
00123 }
00124 
00125 /*
00126 -------------------------
00127 ATST_Hunt
00128 -------------------------`
00129 */
00130 void ATST_Hunt( qboolean visible, qboolean advance )
00131 {
00132 
00133         if ( NPCInfo->goalEntity == NULL )
00134         {//hunt
00135                 NPCInfo->goalEntity = NPC->enemy;
00136         }
00137 
00138         NPCInfo->combatMove = qtrue;
00139 
00140         NPC_MoveToGoal( qtrue );
00141 
00142 }
00143 
00144 /*
00145 -------------------------
00146 ATST_Ranged
00147 -------------------------
00148 */
00149 void ATST_Ranged( qboolean visible, qboolean advance, qboolean altAttack )
00150 {
00151 
00152         if ( TIMER_Done( NPC, "atkDelay" ) && visible ) // Attack?
00153         {
00154                 TIMER_Set( NPC, "atkDelay", Q_irand( 500, 3000 ) );
00155 
00156                 if (altAttack)
00157                 {
00158                         ucmd.buttons |= BUTTON_ATTACK|BUTTON_ALT_ATTACK;
00159                 }
00160                 else
00161                 {
00162                         ucmd.buttons |= BUTTON_ATTACK;
00163                 }
00164         }
00165 
00166         if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00167         {
00168                 ATST_Hunt( visible, advance );
00169         }
00170 }
00171 
00172 /*
00173 -------------------------
00174 ATST_Attack
00175 -------------------------
00176 */
00177 void ATST_Attack( void )
00178 {
00179         qboolean        altAttack=qfalse;
00180         int                     blasterTest,chargerTest,weapon;
00181         float           distance;       
00182         distance_e      distRate;
00183         qboolean        visible;
00184         qboolean        advance;
00185 
00186         if ( NPC_CheckEnemyExt(qfalse) == qfalse )
00187         {
00188                 NPC->enemy = NULL;
00189                 return;
00190         }
00191 
00192         NPC_FaceEnemy( qtrue );
00193 
00194         // Rate our distance to the target, and our visibilty
00195         distance        = (int) DistanceHorizontalSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin ); 
00196         distRate        = ( distance > MIN_MELEE_RANGE_SQR ) ? DIST_LONG : DIST_MELEE;
00197         visible         = NPC_ClearLOS4( NPC->enemy );
00198         advance         = (qboolean)(distance > MIN_DISTANCE_SQR);
00199 
00200         // If we cannot see our target, move to see it
00201         if ( visible == qfalse )
00202         {
00203                 if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00204                 {
00205                         ATST_Hunt( visible, advance );
00206                         return;
00207                 }
00208         }
00209 
00210         // Decide what type of attack to do
00211         switch ( distRate )
00212         {
00213         case DIST_MELEE:
00214 //              NPC_ChangeWeapon( WP_ATST_MAIN );
00215                 break;
00216 
00217         case DIST_LONG:
00218 
00219 //              NPC_ChangeWeapon( WP_ATST_SIDE );
00220                 //rwwFIXMEFIXME: make atst weaps work.
00221 
00222                 // See if the side weapons are there
00223                 blasterTest = trap_G2API_GetSurfaceRenderStatus( NPC->ghoul2, 0, "head_light_blaster_cann" );
00224                 chargerTest = trap_G2API_GetSurfaceRenderStatus( NPC->ghoul2, 0, "head_concussion_charger" );
00225 
00226                 // It has both side weapons
00227                 if ( blasterTest != -1
00228                         && !(blasterTest&TURN_OFF)  
00229                         && chargerTest != -1
00230                         && !(chargerTest&TURN_OFF))
00231                 {
00232                         weapon = Q_irand( 0, 1);        // 0 is blaster, 1 is charger (ALT SIDE)
00233 
00234                         if (weapon)                             // Fire charger
00235                         {
00236                                 altAttack = qtrue;
00237                         }
00238                         else
00239                         {
00240                                 altAttack = qfalse;
00241                         }
00242 
00243                 }
00244                 else if (blasterTest != -1
00245                         && !(blasterTest & TURN_OFF))   // Blaster is on
00246                 {
00247                         altAttack = qfalse;
00248                 }
00249                 else if (chargerTest != -1
00250                         &&!(chargerTest & TURN_OFF))    // Blaster is on
00251                 {
00252                         altAttack = qtrue;
00253                 }
00254                 else 
00255                 {
00256                         NPC_ChangeWeapon( WP_NONE );
00257                 }
00258                 break;
00259         }
00260 
00261         NPC_FaceEnemy( qtrue );
00262 
00263         ATST_Ranged( visible, advance,altAttack );
00264 }
00265 
00266 /*
00267 -------------------------
00268 ATST_Patrol
00269 -------------------------
00270 */
00271 void ATST_Patrol( void )
00272 {
00273         if ( NPC_CheckPlayerTeamStealth() )
00274         {
00275                 NPC_UpdateAngles( qtrue, qtrue );
00276                 return;
00277         }
00278 
00279         //If we have somewhere to go, then do that
00280         if (!NPC->enemy)
00281         {
00282                 if ( UpdateGoal() )
00283                 {
00284                         ucmd.buttons |= BUTTON_WALKING;
00285                         NPC_MoveToGoal( qtrue );
00286                         NPC_UpdateAngles( qtrue, qtrue );
00287                 }
00288         }
00289 
00290 }
00291 
00292 /*
00293 -------------------------
00294 ATST_Idle
00295 -------------------------
00296 */
00297 void ATST_Idle( void )
00298 {
00299 
00300         NPC_BSIdle();
00301 
00302         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_NORMAL );
00303 }
00304 
00305 /*
00306 -------------------------
00307 NPC_BSDroid_Default
00308 -------------------------
00309 */
00310 void NPC_BSATST_Default( void )
00311 {
00312         if ( NPC->enemy )
00313         {
00314                 if( (NPCInfo->scriptFlags & SCF_CHASE_ENEMIES) )
00315                 {
00316                         NPCInfo->goalEntity = NPC->enemy;
00317                 }
00318                 ATST_Attack();
00319         }
00320         else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00321         {
00322                 ATST_Patrol();
00323         } 
00324         else
00325         {
00326                 ATST_Idle();
00327         }
00328 }