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
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
00026
00027 RegisterItem( BG_FindItemForWeapon( WP_BOWCASTER ));
00028 RegisterItem( BG_FindItemForWeapon( WP_ROCKET_LAUNCHER ));
00029
00030 G_EffectIndex( "env/med_explode2" );
00031
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
00061
00062
00063
00064
00065
00066 void G_ATSTCheckPain( gentity_t *self, gentity_t *other, int damage )
00067 {
00068
00069
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
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 }
00114
00115
00116
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
00128
00129
00130 void ATST_Hunt( qboolean visible, qboolean advance )
00131 {
00132
00133 if ( NPCInfo->goalEntity == NULL )
00134 {
00135 NPCInfo->goalEntity = NPC->enemy;
00136 }
00137
00138 NPCInfo->combatMove = qtrue;
00139
00140 NPC_MoveToGoal( qtrue );
00141
00142 }
00143
00144
00145
00146
00147
00148
00149 void ATST_Ranged( qboolean visible, qboolean advance, qboolean altAttack )
00150 {
00151
00152 if ( TIMER_Done( NPC, "atkDelay" ) && visible )
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
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
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
00201 if ( visible == qfalse )
00202 {
00203 if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00204 {
00205 ATST_Hunt( visible, advance );
00206 return;
00207 }
00208 }
00209
00210
00211 switch ( distRate )
00212 {
00213 case DIST_MELEE:
00214
00215 break;
00216
00217 case DIST_LONG:
00218
00219
00220
00221
00222
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
00227 if ( blasterTest != -1
00228 && !(blasterTest&TURN_OFF)
00229 && chargerTest != -1
00230 && !(chargerTest&TURN_OFF))
00231 {
00232 weapon = Q_irand( 0, 1);
00233
00234 if (weapon)
00235 {
00236 altAttack = qtrue;
00237 }
00238 else
00239 {
00240 altAttack = qfalse;
00241 }
00242
00243 }
00244 else if (blasterTest != -1
00245 && !(blasterTest & TURN_OFF))
00246 {
00247 altAttack = qfalse;
00248 }
00249 else if (chargerTest != -1
00250 &&!(chargerTest & TURN_OFF))
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
00269
00270
00271 void ATST_Patrol( void )
00272 {
00273 if ( NPC_CheckPlayerTeamStealth() )
00274 {
00275 NPC_UpdateAngles( qtrue, qtrue );
00276 return;
00277 }
00278
00279
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
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
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 }