------------------------------
| 351 | |
| 352 | //------------------------------ |
| 353 | static void Howler_Attack( float enemyDist, qboolean howl ) |
| 354 | { |
| 355 | int dmg = (NPCInfo->localState==LSTATE_BERZERK)?5:2; |
| 356 | |
| 357 | if ( !TIMER_Exists( NPC, "attacking" )) |
| 358 | { |
| 359 | int attackAnim = BOTH_GESTURE1; |
| 360 | // Going to do an attack |
| 361 | if ( NPC->enemy && NPC->enemy->client && PM_InKnockDown( &NPC->enemy->client->ps ) |
| 362 | && enemyDist <= MIN_DISTANCE ) |
| 363 | { |
| 364 | attackAnim = BOTH_ATTACK2; |
| 365 | } |
| 366 | else if ( !Q_irand( 0, 4 ) || howl ) |
| 367 | {//howl attack |
| 368 | //G_SoundOnEnt( NPC, CHAN_VOICE, "sound/chars/howler/howl.mp3" ); |
| 369 | } |
| 370 | else if ( enemyDist > MIN_DISTANCE && Q_irand( 0, 1 ) ) |
| 371 | {//lunge attack |
| 372 | //jump foward |
| 373 | vec3_t fwd, yawAng = {0, NPC->client->ps.viewangles[YAW], 0}; |
| 374 | AngleVectors( yawAng, fwd, NULL, NULL ); |
| 375 | VectorScale( fwd, (enemyDist*3.0f), NPC->client->ps.velocity ); |
| 376 | NPC->client->ps.velocity[2] = 200; |
| 377 | NPC->client->ps.groundEntityNum = ENTITYNUM_NONE; |
| 378 | |
| 379 | attackAnim = BOTH_ATTACK1; |
| 380 | } |
| 381 | else |
| 382 | {//tongue attack |
| 383 | attackAnim = BOTH_ATTACK2; |
| 384 | } |
| 385 | |
| 386 | NPC_SetAnim( NPC, SETANIM_BOTH, attackAnim, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_RESTART ); |
| 387 | if ( NPCInfo->localState == LSTATE_BERZERK ) |
| 388 | {//attack again right away |
| 389 | TIMER_Set( NPC, "attacking", NPC->client->ps.legsAnimTimer ); |
| 390 | } |
| 391 | else |
| 392 | { |
| 393 | TIMER_Set( NPC, "attacking", NPC->client->ps.legsAnimTimer + Q_irand( 0, 1500 ) );//FIXME: base on skill |
| 394 | TIMER_Set( NPC, "standing", -level.time ); |
| 395 | TIMER_Set( NPC, "walking", -level.time ); |
| 396 | TIMER_Set( NPC, "running", NPC->client->ps.legsAnimTimer + 5000 ); |
| 397 | } |
| 398 | |
| 399 | TIMER_Set( NPC, "attack_dmg", 200 ); // level two damage |
| 400 | } |
| 401 | |
| 402 | // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks |
| 403 | switch ( NPC->client->ps.legsAnim ) |
| 404 | { |
| 405 | case BOTH_ATTACK1: |
| 406 | case BOTH_MELEE1: |
| 407 | if ( NPC->client->ps.legsAnimTimer > 650//more than 13 frames left |
| 408 | && PM_AnimLength( NPC->client->clientInfo.animFileIndex, (animNumber_t)NPC->client->ps.legsAnim ) - NPC->client->ps.legsAnimTimer >= 800 )//at least 16 frames into anim |
| 409 | { |
| 410 | Howler_TryDamage( dmg, qfalse, qfalse ); |
no test coverage detected