00001 #include "b_local.h"
00002
00003
00004 #define MIN_DISTANCE 54
00005 #define MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE )
00006
00007 #define MAX_DISTANCE 128
00008 #define MAX_DISTANCE_SQR ( MAX_DISTANCE * MAX_DISTANCE )
00009
00010 #define LSTATE_CLEAR 0
00011 #define LSTATE_WAITING 1
00012
00013
00014
00015
00016
00017
00018 void NPC_Howler_Precache( void )
00019 {
00020 }
00021
00022
00023
00024
00025
00026
00027
00028 void Howler_Idle( void )
00029 {
00030 }
00031
00032
00033
00034
00035
00036
00037
00038 void Howler_Patrol( void )
00039 {
00040 vec3_t dif;
00041
00042 NPCInfo->localState = LSTATE_CLEAR;
00043
00044
00045 if ( UpdateGoal() )
00046 {
00047 ucmd.buttons &= ~BUTTON_WALKING;
00048 NPC_MoveToGoal( qtrue );
00049 }
00050 else
00051 {
00052 if ( TIMER_Done( NPC, "patrolTime" ))
00053 {
00054 TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
00055 }
00056 }
00057
00058
00059 VectorSubtract( g_entities[0].r.currentOrigin, NPC->r.currentOrigin, dif );
00060
00061 if ( VectorLengthSquared( dif ) < 256 * 256 )
00062 {
00063 G_SetEnemy( NPC, &g_entities[0] );
00064 }
00065
00066 if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
00067 {
00068 Howler_Idle();
00069 return;
00070 }
00071 }
00072
00073
00074
00075
00076
00077
00078 void Howler_Move( qboolean visible )
00079 {
00080 if ( NPCInfo->localState != LSTATE_WAITING )
00081 {
00082 NPCInfo->goalEntity = NPC->enemy;
00083 NPC_MoveToGoal( qtrue );
00084 NPCInfo->goalRadius = MAX_DISTANCE;
00085 }
00086 }
00087
00088
00089 void Howler_TryDamage( gentity_t *enemy, int damage )
00090 {
00091 vec3_t end, dir;
00092 trace_t tr;
00093
00094 if ( !enemy )
00095 {
00096 return;
00097 }
00098
00099 AngleVectors( NPC->client->ps.viewangles, dir, NULL, NULL );
00100 VectorMA( NPC->r.currentOrigin, MIN_DISTANCE, dir, end );
00101
00102
00103 trap_Trace( &tr, NPC->r.currentOrigin, vec3_origin, vec3_origin, end, NPC->s.number, MASK_SHOT );
00104
00105 if ( tr.entityNum != ENTITYNUM_WORLD )
00106 {
00107 G_Damage( &g_entities[tr.entityNum], NPC, NPC, dir, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00108 }
00109 }
00110
00111
00112 void Howler_Attack( void )
00113 {
00114 if ( !TIMER_Exists( NPC, "attacking" ))
00115 {
00116
00117 TIMER_Set( NPC, "attacking", 1700 + random() * 200 );
00118 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00119
00120 TIMER_Set( NPC, "attack_dmg", 200 );
00121 }
00122
00123
00124 if ( TIMER_Done2( NPC, "attack_dmg", qtrue ))
00125 {
00126 Howler_TryDamage( NPC->enemy, 5 );
00127 }
00128
00129
00130 TIMER_Done2( NPC, "attacking", qtrue );
00131 }
00132
00133
00134 void Howler_Combat( void )
00135 {
00136 float distance;
00137 qboolean advance;
00138
00139
00140 if ( !NPC_ClearLOS4( NPC->enemy ) || UpdateGoal( ))
00141 {
00142 NPCInfo->combatMove = qtrue;
00143 NPCInfo->goalEntity = NPC->enemy;
00144 NPCInfo->goalRadius = MAX_DISTANCE;
00145
00146 NPC_MoveToGoal( qtrue );
00147 return;
00148 }
00149
00150
00151 NPC_FaceEnemy( qtrue );
00152
00153 distance = DistanceHorizontalSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00154 advance = (qboolean)( distance > MIN_DISTANCE_SQR ? qtrue : qfalse );
00155
00156 if (( advance || NPCInfo->localState == LSTATE_WAITING ) && TIMER_Done( NPC, "attacking" ))
00157 {
00158 if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00159 {
00160 NPCInfo->localState = LSTATE_CLEAR;
00161 }
00162 else
00163 {
00164 Howler_Move( 1 );
00165 }
00166 }
00167 else
00168 {
00169 Howler_Attack();
00170 }
00171 }
00172
00173
00174
00175
00176
00177
00178 void NPC_Howler_Pain( gentity_t *self, gentity_t *attacker, int damage )
00179 {
00180 if ( damage >= 10 )
00181 {
00182 TIMER_Remove( self, "attacking" );
00183 TIMER_Set( self, "takingPain", 2900 );
00184
00185 VectorCopy( self->NPC->lastPathAngles, self->s.angles );
00186
00187 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00188
00189 if ( self->NPC )
00190 {
00191 self->NPC->localState = LSTATE_WAITING;
00192 }
00193 }
00194 }
00195
00196
00197
00198
00199
00200
00201
00202 void NPC_BSHowler_Default( void )
00203 {
00204 if ( NPC->enemy )
00205 {
00206 Howler_Combat();
00207 }
00208 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00209 {
00210 Howler_Patrol();
00211 }
00212 else
00213 {
00214 Howler_Idle();
00215 }
00216
00217 NPC_UpdateAngles( qtrue, qtrue );
00218 }