00001
00002 #include "g_headers.h"
00003
00004
00005 #include "b_local.h"
00006
00007 extern void G_GetBoltPosition( gentity_t *self, int boltIndex, vec3_t pos, int modelIndex );
00008
00009
00010 #define MIN_DISTANCE 128
00011 #define MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE )
00012
00013 #define MAX_DISTANCE 1024
00014 #define MAX_DISTANCE_SQR ( MAX_DISTANCE * MAX_DISTANCE )
00015
00016 #define LSTATE_CLEAR 0
00017 #define LSTATE_WAITING 1
00018
00019 void Rancor_SetBolts( gentity_t *self )
00020 {
00021 if ( self && self->client )
00022 {
00023 renderInfo_t *ri = &self->client->renderInfo;
00024 ri->handRBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*r_hand" );
00025 ri->handLBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_hand" );
00026 ri->headBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*head_eyes" );
00027 ri->torsoBolt = trap_G2API_AddBolt( self->ghoul2, 0, "jaw_bone" );
00028 }
00029 }
00030
00031
00032
00033
00034
00035
00036 void NPC_Rancor_Precache( void )
00037 {
00038 int i;
00039 for ( i = 1; i < 3; i ++ )
00040 {
00041 G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", i) );
00042 }
00043 G_SoundIndex( "sound/chars/rancor/swipehit.wav" );
00044 G_SoundIndex( "sound/chars/rancor/chomp.wav" );
00045 }
00046
00047
00048
00049
00050
00051
00052
00053 void Rancor_Idle( void )
00054 {
00055 NPCInfo->localState = LSTATE_CLEAR;
00056
00057
00058 if ( UpdateGoal() )
00059 {
00060 ucmd.buttons &= ~BUTTON_WALKING;
00061 NPC_MoveToGoal( qtrue );
00062 }
00063 }
00064
00065
00066 qboolean Rancor_CheckRoar( gentity_t *self )
00067 {
00068 if ( !self->wait )
00069 {
00070 self->wait = 1;
00071 self->client->ps.eFlags2 |= EF2_ALERTED;
00072 NPC_SetAnim( self, SETANIM_BOTH, BOTH_STAND1TO2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00073 TIMER_Set( self, "rageTime", self->client->ps.legsTimer );
00074 return qtrue;
00075 }
00076 return qfalse;
00077 }
00078
00079
00080
00081
00082
00083 void Rancor_Patrol( void )
00084 {
00085 NPCInfo->localState = LSTATE_CLEAR;
00086
00087
00088 if ( UpdateGoal() )
00089 {
00090 ucmd.buttons &= ~BUTTON_WALKING;
00091 NPC_MoveToGoal( qtrue );
00092 }
00093 else
00094 {
00095 if ( TIMER_Done( NPC, "patrolTime" ))
00096 {
00097 TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
00098 }
00099 }
00100
00101 if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
00102 {
00103 Rancor_Idle();
00104 return;
00105 }
00106 Rancor_CheckRoar( NPC );
00107 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00108 }
00109
00110
00111
00112
00113
00114
00115 void Rancor_Move( qboolean visible )
00116 {
00117 if ( NPCInfo->localState != LSTATE_WAITING )
00118 {
00119 NPCInfo->goalEntity = NPC->enemy;
00120 if ( !NPC_MoveToGoal( qtrue ) )
00121 {
00122 NPCInfo->consecutiveBlockedMoves++;
00123 }
00124 else
00125 {
00126 NPCInfo->consecutiveBlockedMoves = 0;
00127 }
00128 NPCInfo->goalRadius = MAX_DISTANCE;
00129 }
00130 }
00131
00132
00133
00134 extern void G_Knockdown( gentity_t *victim );
00135 extern void G_Dismember( gentity_t *ent, gentity_t *enemy, vec3_t point, int limbType, float limbRollBase, float limbPitchBase, int deathAnim, qboolean postDeath );
00136
00137 extern float NPC_EntRangeFromBolt( gentity_t *targEnt, int boltIndex );
00138 extern int NPC_GetEntsNearBolt( int *radiusEnts, float radius, int boltIndex, vec3_t boltOrg );
00139
00140 void Rancor_DropVictim( gentity_t *self )
00141 {
00142
00143
00144 if ( self->activator )
00145 {
00146 if ( self->activator->client )
00147 {
00148 self->activator->client->ps.eFlags2 &= ~EF2_HELD_BY_MONSTER;
00149 self->activator->client->ps.hasLookTarget = qfalse;
00150 self->activator->client->ps.lookTarget = ENTITYNUM_NONE;
00151 self->activator->client->ps.viewangles[ROLL] = 0;
00152 SetClientViewAngle( self->activator, self->activator->client->ps.viewangles );
00153 self->activator->r.currentAngles[PITCH] = self->activator->r.currentAngles[ROLL] = 0;
00154 G_SetAngles( self->activator, self->activator->r.currentAngles );
00155 }
00156 if ( self->activator->health <= 0 )
00157 {
00158
00159 {
00160 if ( self->count == 1 )
00161 {
00162 if ( self->activator->client )
00163 {
00164 self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
00165
00166 }
00167 }
00168 else
00169 {
00170 if ( self->activator->client )
00171 {
00172 self->activator->client->ps.eFlags |= EF_NODRAW;
00173 }
00174
00175 }
00176 }
00177 }
00178 else
00179 {
00180 if ( self->activator->NPC )
00181 {
00182 self->activator->NPC->nextBStateThink = level.time;
00183 }
00184
00185 self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
00186 }
00187 if ( self->enemy == self->activator )
00188 {
00189 self->enemy = NULL;
00190 }
00191 self->activator = NULL;
00192 }
00193 self->count = 0;
00194 }
00195
00196 void Rancor_Swing( qboolean tryGrab )
00197 {
00198 int radiusEntNums[128];
00199 int numEnts;
00200 const float radius = 88;
00201 const float radiusSquared = (radius*radius);
00202 int i;
00203 vec3_t boltOrg;
00204
00205 numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handRBolt, boltOrg );
00206
00207 for ( i = 0; i < numEnts; i++ )
00208 {
00209 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00210 if ( !radiusEnt->inuse )
00211 {
00212 continue;
00213 }
00214
00215 if ( radiusEnt == NPC )
00216 {
00217 continue;
00218 }
00219
00220 if ( radiusEnt->client == NULL )
00221 {
00222 continue;
00223 }
00224
00225 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00226 {
00227 continue;
00228 }
00229
00230 if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared )
00231 {
00232 if ( tryGrab
00233 && NPC->count != 1
00234 && radiusEnt->client->NPC_class != CLASS_RANCOR
00235 && radiusEnt->client->NPC_class != CLASS_GALAKMECH
00236 && radiusEnt->client->NPC_class != CLASS_ATST
00237 && radiusEnt->client->NPC_class != CLASS_GONK
00238 && radiusEnt->client->NPC_class != CLASS_R2D2
00239 && radiusEnt->client->NPC_class != CLASS_R5D2
00240 && radiusEnt->client->NPC_class != CLASS_MARK1
00241 && radiusEnt->client->NPC_class != CLASS_MARK2
00242 && radiusEnt->client->NPC_class != CLASS_MOUSE
00243 && radiusEnt->client->NPC_class != CLASS_PROBE
00244 && radiusEnt->client->NPC_class != CLASS_SEEKER
00245 && radiusEnt->client->NPC_class != CLASS_REMOTE
00246 && radiusEnt->client->NPC_class != CLASS_SENTRY
00247 && radiusEnt->client->NPC_class != CLASS_INTERROGATOR
00248 && radiusEnt->client->NPC_class != CLASS_VEHICLE )
00249 {
00250 if ( NPC->count == 2 )
00251 {
00252 TIMER_Remove( NPC, "clearGrabbed" );
00253 Rancor_DropVictim( NPC );
00254 }
00255 NPC->enemy = radiusEnt;
00256 radiusEnt->client->ps.eFlags2 |= EF2_HELD_BY_MONSTER;
00257
00258 radiusEnt->client->ps.hasLookTarget = qtrue;
00259 radiusEnt->client->ps.lookTarget = NPC->s.number;
00260 NPC->activator = radiusEnt;
00261 NPC->count = 1;
00262
00263 TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + Q_irand(500, 2500) );
00264 if ( radiusEnt->health > 0 && radiusEnt->pain )
00265 {
00266 radiusEnt->pain( radiusEnt, NPC, 100 );
00267
00268 }
00269 else if ( radiusEnt->client )
00270 {
00271 radiusEnt->client->ps.forceHandExtend = HANDEXTEND_NONE;
00272 radiusEnt->client->ps.forceHandExtendTime = 0;
00273 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00274 }
00275 }
00276 else
00277 {
00278 vec3_t pushDir;
00279 vec3_t angs;
00280
00281 G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00282
00283
00284
00285
00286
00287
00288
00289 VectorCopy( NPC->client->ps.viewangles, angs );
00290 angs[YAW] += flrand( 25, 50 );
00291 angs[PITCH] = flrand( -25, -15 );
00292 AngleVectors( angs, pushDir, NULL, NULL );
00293 if ( radiusEnt->client->NPC_class != CLASS_RANCOR
00294 && radiusEnt->client->NPC_class != CLASS_ATST )
00295 {
00296 G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 25, 40 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00297 G_Throw( radiusEnt, pushDir, 250 );
00298 if ( radiusEnt->health > 0 )
00299 {
00300 G_Knockdown( radiusEnt );
00301 }
00302 }
00303 }
00304 }
00305 }
00306 }
00307
00308 void Rancor_Smash( void )
00309 {
00310 int radiusEntNums[128];
00311 int numEnts;
00312 const float radius = 128;
00313 const float halfRadSquared = ((radius/2)*(radius/2));
00314 const float radiusSquared = (radius*radius);
00315 float distSq;
00316 int i;
00317 vec3_t boltOrg;
00318
00319 AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse );
00320
00321 numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handLBolt, boltOrg );
00322
00323 for ( i = 0; i < numEnts; i++ )
00324 {
00325 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00326 if ( !radiusEnt->inuse )
00327 {
00328 continue;
00329 }
00330
00331 if ( radiusEnt == NPC )
00332 {
00333 continue;
00334 }
00335
00336 if ( radiusEnt->client == NULL )
00337 {
00338 continue;
00339 }
00340
00341 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00342 {
00343 continue;
00344 }
00345
00346 distSq = DistanceSquared( radiusEnt->r.currentOrigin, boltOrg );
00347 if ( distSq <= radiusSquared )
00348 {
00349 G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00350 if ( distSq < halfRadSquared )
00351 {
00352 G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 10, 25 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00353 }
00354 if ( radiusEnt->health > 0
00355 && radiusEnt->client
00356 && radiusEnt->client->NPC_class != CLASS_RANCOR
00357 && radiusEnt->client->NPC_class != CLASS_ATST )
00358 {
00359 if ( distSq < halfRadSquared
00360 || radiusEnt->client->ps.groundEntityNum != ENTITYNUM_NONE )
00361 {
00362 G_Knockdown( radiusEnt );
00363 }
00364 }
00365 }
00366 }
00367 }
00368
00369 void Rancor_Bite( void )
00370 {
00371 int radiusEntNums[128];
00372 int numEnts;
00373 const float radius = 100;
00374 const float radiusSquared = (radius*radius);
00375 int i;
00376 vec3_t boltOrg;
00377
00378 numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.crotchBolt, boltOrg );
00379
00380 for ( i = 0; i < numEnts; i++ )
00381 {
00382 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00383 if ( !radiusEnt->inuse )
00384 {
00385 continue;
00386 }
00387
00388 if ( radiusEnt == NPC )
00389 {
00390 continue;
00391 }
00392
00393 if ( radiusEnt->client == NULL )
00394 {
00395 continue;
00396 }
00397
00398 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00399 {
00400 continue;
00401 }
00402
00403 if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared )
00404 {
00405 G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 15, 30 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00406 if ( radiusEnt->health <= 0 && radiusEnt->client )
00407 {
00408 if ( !Q_irand( 0, 1 ) )
00409 {
00410 int hitLoc = Q_irand( G2_MODELPART_HEAD, G2_MODELPART_RLEG );
00411 if ( hitLoc == G2_MODELPART_HEAD )
00412 {
00413 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATH17, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00414 }
00415 else if ( hitLoc == G2_MODELPART_WAIST )
00416 {
00417 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATHBACKWARD2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00418 }
00419
00420
00421 G_Dismember( radiusEnt, NPC, radiusEnt->r.currentOrigin, hitLoc, 90, 0, radiusEnt->client->ps.torsoAnim, qtrue);
00422
00423 }
00424 }
00425 G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00426 }
00427 }
00428 }
00429
00430 extern void TossClientItems( gentity_t *self );
00431 void Rancor_Attack( float distance, qboolean doCharge )
00432 {
00433 if ( !TIMER_Exists( NPC, "attacking" ) )
00434 {
00435 if ( NPC->count == 2 && NPC->activator )
00436 {
00437 }
00438 else if ( NPC->count == 1 && NPC->activator )
00439 {
00440 if ( NPC->activator->health > 0 && Q_irand( 0, 1 ) )
00441 {
00442 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00443 TIMER_Set( NPC, "attack_dmg", 450 );
00444 }
00445 else
00446 {
00447 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK3, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00448 TIMER_Set( NPC, "attack_dmg", 900 );
00449
00450 if ( NPC->activator->health > 0 && NPC->activator->client )
00451 {
00452 G_AddEvent( NPC->activator, Q_irand(EV_DEATH1, EV_DEATH3), 0 );
00453 NPC_SetAnim( NPC->activator, SETANIM_TORSO, BOTH_FALLDEATH1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00454 if ( NPC->activator->NPC )
00455 {
00456 TossClientItems( NPC );
00457 NPC->activator->NPC->nextBStateThink = Q3_INFINITE;
00458 }
00459 }
00460 }
00461 }
00462 else if ( NPC->enemy->health > 0 && doCharge )
00463 {
00464 vec3_t fwd, yawAng;
00465 VectorSet( yawAng, 0, NPC->client->ps.viewangles[YAW], 0 );
00466 AngleVectors( yawAng, fwd, NULL, NULL );
00467 VectorScale( fwd, distance*1.5f, NPC->client->ps.velocity );
00468 NPC->client->ps.velocity[2] = 150;
00469 NPC->client->ps.groundEntityNum = ENTITYNUM_NONE;
00470
00471 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_MELEE2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00472 TIMER_Set( NPC, "attack_dmg", 1250 );
00473 }
00474 else if ( !Q_irand(0, 1) )
00475 {
00476 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_MELEE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00477 TIMER_Set( NPC, "attack_dmg", 1000 );
00478 }
00479 else
00480 {
00481 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00482 TIMER_Set( NPC, "attack_dmg", 1000 );
00483 }
00484
00485 TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + random() * 200 );
00486 }
00487
00488
00489
00490 if ( TIMER_Done2( NPC, "attack_dmg", qtrue ) )
00491 {
00492 vec3_t shakePos;
00493 switch ( NPC->client->ps.legsAnim )
00494 {
00495 case BOTH_MELEE1:
00496 Rancor_Smash();
00497 G_GetBoltPosition( NPC, NPC->client->renderInfo.handLBolt, shakePos, 0 );
00498 G_ScreenShake( shakePos, NULL, 4.0f, 1000, qfalse );
00499
00500 break;
00501 case BOTH_MELEE2:
00502 Rancor_Bite();
00503 TIMER_Set( NPC, "attack_dmg2", 450 );
00504 break;
00505 case BOTH_ATTACK1:
00506 if ( NPC->count == 1 && NPC->activator )
00507 {
00508 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, Q_irand( 25, 40 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00509 if ( NPC->activator->health <= 0 )
00510 {
00511
00512
00513 G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_HEAD, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00514
00515 NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00516 NPC->activator->client->ps.forceHandExtendTime = 0;
00517 NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00518 }
00519 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00520 }
00521 break;
00522 case BOTH_ATTACK2:
00523
00524 Rancor_Swing( qtrue );
00525 break;
00526 case BOTH_ATTACK3:
00527 if ( NPC->count == 1 && NPC->activator )
00528 {
00529
00530 if ( NPC->activator->client )
00531 {
00532
00533 G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00534
00535 }
00536
00537 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );
00538 if ( NPC->activator->client )
00539 {
00540 NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00541 NPC->activator->client->ps.forceHandExtendTime = 0;
00542 NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00543 }
00544 TIMER_Set( NPC, "attack_dmg2", 1350 );
00545 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00546 G_AddEvent( NPC->activator, EV_JUMP, NPC->activator->health );
00547 }
00548 break;
00549 }
00550 }
00551 else if ( TIMER_Done2( NPC, "attack_dmg2", qtrue ) )
00552 {
00553 switch ( NPC->client->ps.legsAnim )
00554 {
00555 case BOTH_MELEE1:
00556 break;
00557 case BOTH_MELEE2:
00558 Rancor_Bite();
00559 break;
00560 case BOTH_ATTACK1:
00561 break;
00562 case BOTH_ATTACK2:
00563 break;
00564 case BOTH_ATTACK3:
00565 if ( NPC->count == 1 && NPC->activator )
00566 {
00567 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00568
00569
00570 if ( NPC->activator->health > 0 )
00571 {
00572
00573
00574 G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00575
00576
00577 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );
00578 NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00579 NPC->activator->client->ps.forceHandExtendTime = 0;
00580 NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00581 G_AddEvent( NPC->activator, EV_JUMP, NPC->activator->health );
00582 }
00583 if ( NPC->activator->client )
00584 {
00585 NPC->activator->client->ps.eFlags |= EF_NODRAW;
00586 }
00587 NPC->count = 2;
00588 TIMER_Set( NPC, "clearGrabbed", 2600 );
00589 }
00590 break;
00591 }
00592 }
00593 else if ( NPC->client->ps.legsAnim == BOTH_ATTACK2 )
00594 {
00595 if ( NPC->client->ps.legsTimer >= 1200 && NPC->client->ps.legsTimer <= 1350 )
00596 {
00597 if ( Q_irand( 0, 2 ) )
00598 {
00599 Rancor_Swing( qfalse );
00600 }
00601 else
00602 {
00603 Rancor_Swing( qtrue );
00604 }
00605 }
00606 else if ( NPC->client->ps.legsTimer >= 1100 && NPC->client->ps.legsTimer <= 1550 )
00607 {
00608 Rancor_Swing( qtrue );
00609 }
00610 }
00611
00612
00613 TIMER_Done2( NPC, "attacking", qtrue );
00614 }
00615
00616
00617 void Rancor_Combat( void )
00618 {
00619 if ( NPC->count )
00620 {
00621 if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00622 {
00623 NPCInfo->localState = LSTATE_CLEAR;
00624 }
00625 else
00626 {
00627 Rancor_Attack( 0, qfalse );
00628 }
00629 NPC_UpdateAngles( qtrue, qtrue );
00630 return;
00631 }
00632
00633 if ( !NPC_ClearLOS4( NPC->enemy ) )
00634 {
00635 NPCInfo->combatMove = qtrue;
00636 NPCInfo->goalEntity = NPC->enemy;
00637 NPCInfo->goalRadius = MIN_DISTANCE;
00638
00639 if ( !NPC_MoveToGoal( qtrue ) )
00640 {
00641 TIMER_Set( NPC, "lookForNewEnemy", 0 );
00642 NPCInfo->consecutiveBlockedMoves++;
00643 }
00644 else
00645 {
00646 NPCInfo->consecutiveBlockedMoves = 0;
00647 }
00648 return;
00649 }
00650
00651
00652 NPC_FaceEnemy( qtrue );
00653
00654 {
00655 float distance;
00656 qboolean advance;
00657 qboolean doCharge;
00658
00659 distance = Distance( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00660 advance = (qboolean)( distance > (NPC->r.maxs[0]+MIN_DISTANCE) ? qtrue : qfalse );
00661 doCharge = qfalse;
00662
00663 if ( advance )
00664 {
00665 vec3_t yawOnlyAngles;
00666 VectorSet( yawOnlyAngles, 0, NPC->r.currentAngles[YAW], 0 );
00667 if ( NPC->enemy->health > 0
00668 && fabs(distance-250) <= 80
00669 && InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, yawOnlyAngles, 30, 30 ) )
00670 {
00671 if ( !Q_irand( 0, 9 ) )
00672 {
00673 doCharge = qtrue;
00674 advance = qfalse;
00675 }
00676 }
00677 }
00678
00679 if (( advance ) && TIMER_Done( NPC, "attacking" ))
00680 {
00681 if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00682 {
00683 NPCInfo->localState = LSTATE_CLEAR;
00684 }
00685 else
00686 {
00687 Rancor_Move( 1 );
00688 }
00689 }
00690 else
00691 {
00692 Rancor_Attack( distance, doCharge );
00693 }
00694 }
00695 }
00696
00697
00698
00699
00700
00701
00702
00703 void NPC_Rancor_Pain( gentity_t *self, gentity_t *attacker, int damage )
00704 {
00705 qboolean hitByRancor = qfalse;
00706 if ( attacker&&attacker->client&&attacker->client->NPC_class==CLASS_RANCOR )
00707 {
00708 hitByRancor = qtrue;
00709 }
00710 if ( attacker
00711 && attacker->inuse
00712 && attacker != self->enemy
00713 && !(attacker->flags&FL_NOTARGET) )
00714 {
00715 if ( !self->count )
00716 {
00717 if ( (!attacker->s.number&&!Q_irand(0,3))
00718 || !self->enemy
00719 || self->enemy->health == 0
00720 || (self->enemy->client&&self->enemy->client->NPC_class == CLASS_RANCOR)
00721 || (self->NPC && self->NPC->consecutiveBlockedMoves>=10 && DistanceSquared( attacker->r.currentOrigin, self->r.currentOrigin ) < DistanceSquared( self->enemy->r.currentOrigin, self->r.currentOrigin )) )
00722 {
00723
00724 G_SetEnemy( self, attacker );
00725 TIMER_Set( self, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00726 if ( hitByRancor )
00727 {
00728 TIMER_Set( self, "rancorInfight", Q_irand( 2000, 5000 ) );
00729 }
00730
00731 }
00732 }
00733 }
00734 if ( (hitByRancor|| (self->count==1&&self->activator&&!Q_irand(0,4)) || Q_irand( 0, 200 ) < damage )
00735 && self->client->ps.legsAnim != BOTH_STAND1TO2
00736 && TIMER_Done( self, "takingPain" ) )
00737 {
00738 if ( !Rancor_CheckRoar( self ) )
00739 {
00740 if ( self->client->ps.legsAnim != BOTH_MELEE1
00741 && self->client->ps.legsAnim != BOTH_MELEE2
00742 && self->client->ps.legsAnim != BOTH_ATTACK2 )
00743 {
00744
00745
00746
00747
00748
00749 {
00750 if ( self->health > 100 || hitByRancor )
00751 {
00752 TIMER_Remove( self, "attacking" );
00753
00754 VectorCopy( self->NPC->lastPathAngles, self->s.angles );
00755
00756 if ( self->count == 1 )
00757 {
00758 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00759 }
00760 else
00761 {
00762 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00763 }
00764 TIMER_Set( self, "takingPain", self->client->ps.legsTimer+Q_irand(0, 500) );
00765
00766 if ( self->NPC )
00767 {
00768 self->NPC->localState = LSTATE_WAITING;
00769 }
00770 }
00771 }
00772 }
00773 }
00774
00775
00776
00777
00778
00779
00780
00781 }
00782 }
00783
00784 void Rancor_CheckDropVictim( void )
00785 {
00786 vec3_t mins;
00787 vec3_t maxs;
00788 vec3_t start;
00789 vec3_t end;
00790 trace_t trace;
00791
00792 VectorSet( mins, NPC->activator->r.mins[0]-1, NPC->activator->r.mins[1]-1, 0 );
00793 VectorSet( maxs, NPC->activator->r.maxs[0]+1, NPC->activator->r.maxs[1]+1, 1 );
00794 VectorSet( start, NPC->activator->r.currentOrigin[0], NPC->activator->r.currentOrigin[1], NPC->activator->r.absmin[2] );
00795 VectorSet( end, NPC->activator->r.currentOrigin[0], NPC->activator->r.currentOrigin[1], NPC->activator->r.absmax[2]-1 );
00796
00797 trap_Trace( &trace, start, mins, maxs, end, NPC->activator->s.number, NPC->activator->clipmask );
00798 if ( !trace.allsolid && !trace.startsolid && trace.fraction >= 1.0f )
00799 {
00800 Rancor_DropVictim( NPC );
00801 }
00802 }
00803
00804
00805 void Rancor_Crush(void)
00806 {
00807 gentity_t *crush;
00808
00809 if (!NPC ||
00810 !NPC->client ||
00811 NPC->client->ps.groundEntityNum >= ENTITYNUM_WORLD)
00812 {
00813 return;
00814 }
00815
00816 crush = &g_entities[NPC->client->ps.groundEntityNum];
00817 if (crush->inuse && crush->client && !crush->localAnimIndex)
00818 {
00819 G_Damage(crush, NPC, NPC, NULL, NPC->r.currentOrigin, 200, 0, MOD_CRUSH);
00820 }
00821 }
00822
00823
00824
00825
00826
00827
00828 void NPC_BSRancor_Default( void )
00829 {
00830 AddSightEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, 50 );
00831
00832 Rancor_Crush();
00833
00834 NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00835 if ( NPC->count )
00836 {
00837 NPC->client->ps.eFlags2 |= EF2_USE_ALT_ANIM;
00838 if ( NPC->count == 2 )
00839 {
00840 NPC->client->ps.eFlags2 |= EF2_GENERIC_NPC_FLAG;
00841 }
00842 }
00843 else
00844 {
00845 NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00846 }
00847
00848 if ( TIMER_Done2( NPC, "clearGrabbed", qtrue ) )
00849 {
00850 Rancor_DropVictim( NPC );
00851 }
00852 else if ( NPC->client->ps.legsAnim == BOTH_PAIN2
00853 && NPC->count == 1
00854 && NPC->activator )
00855 {
00856 if ( !Q_irand( 0, 3 ) )
00857 {
00858 Rancor_CheckDropVictim();
00859 }
00860 }
00861 if ( !TIMER_Done( NPC, "rageTime" ) )
00862 {
00863 AddSoundEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, qfalse );
00864 NPC_FaceEnemy( qtrue );
00865 return;
00866 }
00867 if ( NPC->enemy )
00868 {
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878 if ( TIMER_Done(NPC,"angrynoise") )
00879 {
00880 G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/misc/anger%d.wav", Q_irand(1, 3))) );
00881
00882 TIMER_Set( NPC, "angrynoise", Q_irand( 5000, 10000 ) );
00883 }
00884 else
00885 {
00886 AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER_GREAT, qfalse );
00887 }
00888 if ( NPC->count == 2 && NPC->client->ps.legsAnim == BOTH_ATTACK3 )
00889 {
00890 NPC_UpdateAngles( qtrue, qtrue );
00891 return;
00892 }
00893
00894 if( NPC->enemy->client && NPC->enemy->client->NPC_class ==