codemp/game/NPC_AI_MineMonster.c File Reference

#include "b_local.h"

Go to the source code of this file.

Defines

#define MIN_DISTANCE   54
#define MIN_DISTANCE_SQR   ( MIN_DISTANCE * MIN_DISTANCE )
#define MAX_DISTANCE   128
#define MAX_DISTANCE_SQR   ( MAX_DISTANCE * MAX_DISTANCE )
#define LSTATE_CLEAR   0
#define LSTATE_WAITING   1

Functions

void NPC_MineMonster_Precache (void)
void MineMonster_Idle (void)
void MineMonster_Patrol (void)
void MineMonster_Move (qboolean visible)
void MineMonster_TryDamage (gentity_t *enemy, int damage)
void MineMonster_Attack (void)
void MineMonster_Combat (void)
void NPC_MineMonster_Pain (gentity_t *self, gentity_t *attacker, int damage)
void NPC_BSMineMonster_Default (void)


Define Documentation

#define LSTATE_CLEAR   0
 

Definition at line 10 of file NPC_AI_MineMonster.c.

#define LSTATE_WAITING   1
 

Definition at line 11 of file NPC_AI_MineMonster.c.

#define MAX_DISTANCE   128
 

Definition at line 7 of file NPC_AI_MineMonster.c.

#define MAX_DISTANCE_SQR   ( MAX_DISTANCE * MAX_DISTANCE )
 

Definition at line 8 of file NPC_AI_MineMonster.c.

#define MIN_DISTANCE   54
 

Definition at line 4 of file NPC_AI_MineMonster.c.

#define MIN_DISTANCE_SQR   ( MIN_DISTANCE * MIN_DISTANCE )
 

Definition at line 5 of file NPC_AI_MineMonster.c.


Function Documentation

void MineMonster_Attack void   ) 
 

Definition at line 129 of file NPC_AI_MineMonster.c.

References BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK3, BOTH_ATTACK4, entityShared_t::currentOrigin, gentity_s::enemy, MineMonster_TryDamage(), NPC, NPC_SetAnim(), qtrue, gentity_s::r, random, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Done2(), TIMER_Exists(), and TIMER_Set().

Referenced by MineMonster_Combat().

00130 {
00131         if ( !TIMER_Exists( NPC, "attacking" ))
00132         {
00133                 // usually try and play a jump attack if the player somehow got above them....or just really rarely
00134                 if ( NPC->enemy && ((NPC->enemy->r.currentOrigin[2] - NPC->r.currentOrigin[2] > 10 && random() > 0.1f ) 
00135                                                 || random() > 0.8f ))
00136                 {
00137                         // Going to do ATTACK4
00138                         TIMER_Set( NPC, "attacking", 1750 + random() * 200 );
00139                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK4, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00140 
00141                         TIMER_Set( NPC, "attack2_dmg", 950 ); // level two damage
00142                 }
00143                 else if ( random() > 0.5f )
00144                 {
00145                         if ( random() > 0.8f )
00146                         {
00147                                 // Going to do ATTACK3, (rare)
00148                                 TIMER_Set( NPC, "attacking", 850 );
00149                                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK3, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00150 
00151                                 TIMER_Set( NPC, "attack2_dmg", 400 ); // level two damage
00152                         }
00153                         else
00154                         {
00155                                 // Going to do ATTACK1
00156                                 TIMER_Set( NPC, "attacking", 850 );
00157                                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00158 
00159                                 TIMER_Set( NPC, "attack1_dmg", 450 ); // level one damage
00160                         }
00161                 }
00162                 else
00163                 {
00164                         // Going to do ATTACK2
00165                         TIMER_Set( NPC, "attacking", 1250 );
00166                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00167 
00168                         TIMER_Set( NPC, "attack1_dmg", 700 ); // level one damage
00169                 }
00170         }
00171         else
00172         {
00173                 // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks
00174                 if ( TIMER_Done2( NPC, "attack1_dmg", qtrue ))
00175                 {
00176                         MineMonster_TryDamage( NPC->enemy, 5 );
00177                 }
00178                 else if ( TIMER_Done2( NPC, "attack2_dmg", qtrue ))
00179                 {
00180                         MineMonster_TryDamage( NPC->enemy, 10 );
00181                 }
00182         }
00183 
00184         // Just using this to remove the attacking flag at the right time
00185         TIMER_Done2( NPC, "attacking", qtrue );
00186 }

void MineMonster_Combat void   ) 
 

Definition at line 189 of file NPC_AI_MineMonster.c.

References gNPC_t::combatMove, entityShared_t::currentOrigin, DistanceHorizontalSquared(), gentity_s::enemy, gNPC_t::goalEntity, gNPC_t::goalRadius, gNPC_t::localState, LSTATE_CLEAR, LSTATE_WAITING, MAX_DISTANCE, MIN_DISTANCE_SQR, MineMonster_Attack(), MineMonster_Move(), NPC, NPC_ClearLOS4(), NPC_FaceEnemy(), NPC_MoveToGoal(), NPCInfo, qboolean, qfalse, qtrue, gentity_s::r, TIMER_Done(), TIMER_Done2(), and UpdateGoal().

Referenced by NPC_BSMineMonster_Default().

00190 {
00191         float distance;
00192         qboolean advance;
00193 
00194         // If we cannot see our target or we have somewhere to go, then do that
00195         if ( !NPC_ClearLOS4( NPC->enemy ) || UpdateGoal( ))
00196         {
00197                 NPCInfo->combatMove = qtrue;
00198                 NPCInfo->goalEntity = NPC->enemy;
00199                 NPCInfo->goalRadius = MAX_DISTANCE;     // just get us within combat range
00200 
00201                 NPC_MoveToGoal( qtrue );
00202                 return;
00203         }
00204 
00205         // Sometimes I have problems with facing the enemy I'm attacking, so force the issue so I don't look dumb
00206         NPC_FaceEnemy( qtrue );
00207 
00208         distance        = DistanceHorizontalSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );       
00209 
00210         advance = (qboolean)( distance > MIN_DISTANCE_SQR ? qtrue : qfalse  );
00211 
00212         if (( advance || NPCInfo->localState == LSTATE_WAITING ) && TIMER_Done( NPC, "attacking" )) // waiting monsters can't attack
00213         {
00214                 if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00215                 {
00216                         NPCInfo->localState = LSTATE_CLEAR;
00217                 }
00218                 else
00219                 {
00220                         MineMonster_Move( 1 );
00221                 }
00222         }
00223         else
00224         {
00225                 MineMonster_Attack();
00226         }
00227 }

void MineMonster_Idle void   ) 
 

Definition at line 35 of file NPC_AI_MineMonster.c.

References BUTTON_WALKING, usercmd_s::buttons, NPC_MoveToGoal(), qtrue, ucmd, and UpdateGoal().

Referenced by MineMonster_Patrol(), and NPC_BSMineMonster_Default().

00036 {
00037         if ( UpdateGoal() )
00038         {
00039                 ucmd.buttons &= ~BUTTON_WALKING;
00040                 NPC_MoveToGoal( qtrue );
00041         }
00042 }

void MineMonster_Move qboolean  visible  ) 
 

Definition at line 90 of file NPC_AI_MineMonster.c.

References gentity_s::enemy, gNPC_t::goalEntity, gNPC_t::goalRadius, gNPC_t::localState, LSTATE_WAITING, MAX_DISTANCE, NPC, NPC_MoveToGoal(), NPCInfo, and qtrue.

Referenced by MineMonster_Combat().

00091 {
00092         if ( NPCInfo->localState != LSTATE_WAITING )
00093         {
00094                 NPCInfo->goalEntity = NPC->enemy;
00095                 NPC_MoveToGoal( qtrue );
00096                 NPCInfo->goalRadius = MAX_DISTANCE;     // just get us within combat range
00097         }
00098 }

void MineMonster_Patrol void   ) 
 

Definition at line 50 of file NPC_AI_MineMonster.c.

References BUTTON_WALKING, usercmd_s::buttons, crandom, entityShared_t::currentOrigin, g_entities, G_SetEnemy(), gNPC_t::localState, LSTATE_CLEAR, MineMonster_Idle(), NPC, NPC_CheckEnemyExt(), NPC_MoveToGoal(), NPCInfo, qfalse, qtrue, gentity_s::r, TIMER_Done(), TIMER_Set(), ucmd, UpdateGoal(), vec3_t, and VectorSubtract.

Referenced by NPC_BSMineMonster_Default().

00051 {
00052         vec3_t dif;
00053 
00054         NPCInfo->localState = LSTATE_CLEAR;
00055 
00056         //If we have somewhere to go, then do that
00057         if ( UpdateGoal() )
00058         {
00059                 ucmd.buttons &= ~BUTTON_WALKING;
00060                 NPC_MoveToGoal( qtrue );
00061         }
00062         else
00063         {
00064                 if ( TIMER_Done( NPC, "patrolTime" ))
00065                 {
00066                         TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
00067                 }
00068         }
00069 
00070         //rwwFIXMEFIXME: Care about all clients, not just client 0
00071         VectorSubtract( g_entities[0].r.currentOrigin, NPC->r.currentOrigin, dif );
00072 
00073         if ( VectorLengthSquared( dif ) < 256 * 256 )
00074         {
00075                 G_SetEnemy( NPC, &g_entities[0] );
00076         }
00077 
00078         if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
00079         {
00080                 MineMonster_Idle();
00081                 return;
00082         }
00083 }

void MineMonster_TryDamage gentity_t enemy,
int  damage
 

Definition at line 101 of file NPC_AI_MineMonster.c.

References AngleVectors(), CHAN_AUTO, gentity_s::client, entityShared_t::currentOrigin, DAMAGE_NO_KNOCKBACK, trace_t::endpos, trace_t::entityNum, ENTITYNUM_NONE, G_Damage(), G_EffectIndex(), g_entities, G_Sound(), gentity_t, MASK_SHOT, MIN_DISTANCE, MOD_MELEE, NPC, NULL, entityState_s::number, gclient_s::ps, Q_irand(), gentity_s::r, gentity_s::s, trap_Trace(), va(), vec3_origin, vec3_t, VectorMA, and playerState_s::viewangles.

Referenced by MineMonster_Attack().

00102 {
00103         vec3_t  end, dir;
00104         trace_t tr;
00105 
00106         if ( !enemy )
00107         {
00108                 return;
00109         }
00110 
00111         AngleVectors( NPC->client->ps.viewangles, dir, NULL, NULL );
00112         VectorMA( NPC->r.currentOrigin, MIN_DISTANCE, dir, end );
00113 
00114         // Should probably trace from the mouth, but, ah well.
00115         trap_Trace( &tr, NPC->r.currentOrigin, vec3_origin, vec3_origin, end, NPC->s.number, MASK_SHOT );
00116 
00117         if ( tr.entityNum >= 0 && tr.entityNum < ENTITYNUM_NONE )
00118         {
00119                 G_Damage( &g_entities[tr.entityNum], NPC, NPC, dir, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00120                 G_Sound( NPC, CHAN_AUTO, G_EffectIndex(va("sound/chars/mine/misc/bite%i.wav", Q_irand(1,4))));
00121         }
00122         else
00123         {
00124                 G_Sound( NPC, CHAN_AUTO, G_EffectIndex(va("sound/chars/mine/misc/miss%i.wav", Q_irand(1,4))));
00125         }
00126 }

void NPC_BSMineMonster_Default void   ) 
 

Definition at line 262 of file NPC_AI_MineMonster.c.

References gentity_s::enemy, MineMonster_Combat(), MineMonster_Idle(), MineMonster_Patrol(), NPC, NPC_UpdateAngles(), NPCInfo, qtrue, SCF_LOOK_FOR_ENEMIES, and gNPC_t::scriptFlags.

Referenced by NPC_BehaviorSet_MineMonster().

00263 {
00264         if ( NPC->enemy )
00265         {
00266                 MineMonster_Combat();
00267         }
00268         else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00269         {
00270                 MineMonster_Patrol();
00271         }
00272         else
00273         {
00274                 MineMonster_Idle();
00275         }
00276 
00277         NPC_UpdateAngles( qtrue, qtrue );
00278 }

void NPC_MineMonster_Pain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 234 of file NPC_AI_MineMonster.c.

References entityState_s::angles, BOTH_PAIN1, gentity_s::client, EV_PAIN, floor(), G_AddEvent(), gentity_t, gentity_s::health, gNPC_t::lastPathAngles, gNPC_t::localState, LSTATE_WAITING, clientPersistant_t::maxHealth, gentity_s::NPC, NPC_SetAnim(), gclient_s::pers, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Remove(), TIMER_Set(), and VectorCopy.

Referenced by NPC_PainFunc().

00235 {
00236         G_AddEvent( self, EV_PAIN, floor((float)self->health/self->client->pers.maxHealth*100.0f) );
00237 
00238         if ( damage >= 10 )
00239         {
00240                 TIMER_Remove( self, "attacking" );
00241                 TIMER_Remove( self, "attacking1_dmg" );
00242                 TIMER_Remove( self, "attacking2_dmg" );
00243                 TIMER_Set( self, "takingPain", 1350 );
00244 
00245                 VectorCopy( self->NPC->lastPathAngles, self->s.angles );
00246 
00247                 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00248 
00249                 if ( self->NPC )
00250                 {
00251                         self->NPC->localState = LSTATE_WAITING;
00252                 }
00253         }
00254 }

void NPC_MineMonster_Precache void   ) 
 

Definition at line 18 of file NPC_AI_MineMonster.c.

References G_SoundIndex(), and va().

Referenced by NPC_SpawnType(), and SP_NPC_MineMonster().

00019 {
00020         int i;
00021 
00022         for ( i = 0; i < 4; i++ )
00023         {
00024                 G_SoundIndex( va("sound/chars/mine/misc/bite%i.wav", i+1 ));
00025                 G_SoundIndex( va("sound/chars/mine/misc/miss%i.wav", i+1 ));
00026         }
00027 }