File: game\m_boss2.c

    1 /*
    2 Copyright (C) 1997-2001 Id Software, Inc.
    3 
    4 This program is free software; you can redistribute it and/or
    5 modify it under the terms of the GNU General Public License
    6 as published by the Free Software Foundation; either version 2
    7 of the License, or (at your option) any later version.
    8 
    9 This program is distributed in the hope that it will be useful,
   10 but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
   12 
   13 See the GNU General Public License for more details.
   14 
   15 You should have received a copy of the GNU General Public License
   16 along with this program; if not, write to the Free Software
   17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   18 
   19 */
   20 /*
   21 ==============================================================================
   22 
   23 boss2
   24 
   25 ==============================================================================
   26 */
   27 
   28 #include "g_local.h"
   29 #include "m_boss2.h"
   30 
   31 void BossExplode (edict_t *self);
   32 
   33 qboolean infront (edict_t *self, edict_t *other);
   34 
   35 static int      sound_pain1;
   36 static int      sound_pain2;
   37 static int      sound_pain3;
   38 static int      sound_death;
   39 static int      sound_search1;
   40 
   41 void boss2_search (edict_t *self)
   42 {
   43         if (random() < 0.5)
   44                 gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0);
   45 }
   46 
   47 void boss2_run (edict_t *self);
   48 void boss2_stand (edict_t *self);
   49 void boss2_dead (edict_t *self);
   50 void boss2_attack (edict_t *self);
   51 void boss2_attack_mg (edict_t *self);
   52 void boss2_reattack_mg (edict_t *self);
   53 void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
   54 
   55 void Boss2Rocket (edict_t *self)
   56 {
   57         vec3_t  forward, right;
   58         vec3_t  start;
   59         vec3_t  dir;
   60         vec3_t  vec;
   61 
   62         AngleVectors (self->s.angles, forward, right, NULL);
   63 
   64 //1
   65         G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1], forward, right, start);
   66         VectorCopy (self->enemy->s.origin, vec);
   67         vec[2] += self->enemy->viewheight;
   68         VectorSubtract (vec, start, dir);
   69         VectorNormalize (dir);
   70         monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_1);
   71 
   72 //2
   73         G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2], forward, right, start);
   74         VectorCopy (self->enemy->s.origin, vec);
   75         vec[2] += self->enemy->viewheight;
   76         VectorSubtract (vec, start, dir);
   77         VectorNormalize (dir);
   78         monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
   79 
   80 //3
   81         G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3], forward, right, start);
   82         VectorCopy (self->enemy->s.origin, vec);
   83         vec[2] += self->enemy->viewheight;
   84         VectorSubtract (vec, start, dir);
   85         VectorNormalize (dir);
   86         monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_3);
   87 
   88 //4
   89         G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
   90         VectorCopy (self->enemy->s.origin, vec);
   91         vec[2] += self->enemy->viewheight;
   92         VectorSubtract (vec, start, dir);
   93         VectorNormalize (dir);
   94         monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4);
   95 }       
   96 
   97 void boss2_firebullet_right (edict_t *self)
   98 {
   99         vec3_t  forward, right, target;
  100         vec3_t  start;
  101 
  102         AngleVectors (self->s.angles, forward, right, NULL);
  103         G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_R1], forward, right, start);
  104 
  105         VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
  106         target[2] += self->enemy->viewheight;
  107         VectorSubtract (target, start, forward);
  108         VectorNormalize (forward);
  109 
  110         monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_R1);
  111 }       
  112 
  113 void boss2_firebullet_left (edict_t *self)
  114 {
  115         vec3_t  forward, right, target;
  116         vec3_t  start;
  117         
  118         AngleVectors (self->s.angles, forward, right, NULL);
  119         G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_L1], forward, right, start);
  120 
  121         VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
  122 
  123         target[2] += self->enemy->viewheight;
  124         VectorSubtract (target, start, forward);
  125         VectorNormalize (forward);
  126 
  127         monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_L1);
  128 }       
  129 
  130 void Boss2MachineGun (edict_t *self)
  131 {
  132 /*      vec3_t  forward, right;
  133         vec3_t  start;
  134         vec3_t  dir;
  135         vec3_t  vec;
  136         int             flash_number;
  137 
  138         AngleVectors (self->s.angles, forward, right, NULL);
  139 
  140         flash_number = MZ2_BOSS2_MACHINEGUN_1 + (self->s.frame - FRAME_attack10);
  141         G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  142 
  143         VectorCopy (self->enemy->s.origin, vec);
  144         vec[2] += self->enemy->viewheight;
  145         VectorSubtract (vec, start, dir);
  146         VectorNormalize (dir);
  147         monster_fire_bullet (self, start, dir, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
  148 */
  149         boss2_firebullet_left(self);
  150         boss2_firebullet_right(self);
  151 }       
  152 
  153 
  154 mframe_t boss2_frames_stand [] =
  155 {
  156         ai_stand, 0, NULL,
  157         ai_stand, 0, NULL,
  158         ai_stand, 0, NULL,
  159         ai_stand, 0, NULL,
  160         ai_stand, 0, NULL,
  161         ai_stand, 0, NULL,
  162         ai_stand, 0, NULL,
  163         ai_stand, 0, NULL,
  164         ai_stand, 0, NULL,
  165         ai_stand, 0, NULL,
  166         ai_stand, 0, NULL,
  167         ai_stand, 0, NULL,
  168         ai_stand, 0, NULL,
  169         ai_stand, 0, NULL,
  170         ai_stand, 0, NULL,
  171         ai_stand, 0, NULL,
  172         ai_stand, 0, NULL,
  173         ai_stand, 0, NULL,
  174         ai_stand, 0, NULL,
  175         ai_stand, 0, NULL,
  176         ai_stand, 0, NULL
  177 };
  178 mmove_t boss2_move_stand = {FRAME_stand30, FRAME_stand50, boss2_frames_stand, NULL};
  179 
  180 mframe_t boss2_frames_fidget [] =
  181 {
  182         ai_stand, 0, NULL,
  183         ai_stand, 0, NULL,
  184         ai_stand, 0, NULL,
  185         ai_stand, 0, NULL,
  186         ai_stand, 0, NULL,
  187         ai_stand, 0, NULL,
  188         ai_stand, 0, NULL,
  189         ai_stand, 0, NULL,
  190         ai_stand, 0, NULL,
  191         ai_stand, 0, NULL,
  192         ai_stand, 0, NULL,
  193         ai_stand, 0, NULL,
  194         ai_stand, 0, NULL,
  195         ai_stand, 0, NULL,
  196         ai_stand, 0, NULL,
  197         ai_stand, 0, NULL,
  198         ai_stand, 0, NULL,
  199         ai_stand, 0, NULL,
  200         ai_stand, 0, NULL,
  201         ai_stand, 0, NULL,
  202         ai_stand, 0, NULL,
  203         ai_stand, 0, NULL,
  204         ai_stand, 0, NULL,
  205         ai_stand, 0, NULL,
  206         ai_stand, 0, NULL,
  207         ai_stand, 0, NULL,
  208         ai_stand, 0, NULL,
  209         ai_stand, 0, NULL,
  210         ai_stand, 0, NULL,
  211         ai_stand, 0, NULL
  212 };
  213 mmove_t boss2_move_fidget = {FRAME_stand1, FRAME_stand30, boss2_frames_fidget, NULL};
  214 
  215 mframe_t boss2_frames_walk [] =
  216 {
  217         ai_walk,        8,      NULL,
  218         ai_walk,        8,      NULL,
  219         ai_walk,        8,      NULL,
  220         ai_walk,        8,      NULL,
  221         ai_walk,        8,      NULL,
  222         ai_walk,        8,      NULL,
  223         ai_walk,        8,      NULL,
  224         ai_walk,        8,      NULL,
  225         ai_walk,        8,      NULL,
  226         ai_walk,        8,      NULL,
  227         ai_walk,        8,      NULL,
  228         ai_walk,        8,      NULL,
  229         ai_walk,        8,      NULL,
  230         ai_walk,        8,      NULL,
  231         ai_walk,        8,      NULL,
  232         ai_walk,        8,      NULL,
  233         ai_walk,        8,      NULL,
  234         ai_walk,        8,      NULL,
  235         ai_walk,        8,      NULL,
  236         ai_walk,        8,      NULL
  237 };
  238 mmove_t boss2_move_walk = {FRAME_walk1, FRAME_walk20, boss2_frames_walk, NULL};
  239 
  240 
  241 mframe_t boss2_frames_run [] =
  242 {
  243         ai_run, 8,      NULL,
  244         ai_run, 8,      NULL,
  245         ai_run, 8,      NULL,
  246         ai_run, 8,      NULL,
  247         ai_run, 8,      NULL,
  248         ai_run, 8,      NULL,
  249         ai_run, 8,      NULL,
  250         ai_run, 8,      NULL,
  251         ai_run, 8,      NULL,
  252         ai_run, 8,      NULL,
  253         ai_run, 8,      NULL,
  254         ai_run, 8,      NULL,
  255         ai_run, 8,      NULL,
  256         ai_run, 8,      NULL,
  257         ai_run, 8,      NULL,
  258         ai_run, 8,      NULL,
  259         ai_run, 8,      NULL,
  260         ai_run, 8,      NULL,
  261         ai_run, 8,      NULL,
  262         ai_run, 8,      NULL
  263 };
  264 mmove_t boss2_move_run = {FRAME_walk1, FRAME_walk20, boss2_frames_run, NULL};
  265 
  266 mframe_t boss2_frames_attack_pre_mg [] =
  267 {
  268         ai_charge,      1,      NULL,
  269         ai_charge,      1,      NULL,
  270         ai_charge,      1,      NULL,
  271         ai_charge,      1,      NULL,
  272         ai_charge,      1,      NULL,
  273         ai_charge,      1,      NULL,
  274         ai_charge,      1,      NULL,
  275         ai_charge,      1,      NULL,
  276         ai_charge,      1,      boss2_attack_mg
  277 };
  278 mmove_t boss2_move_attack_pre_mg = {FRAME_attack1, FRAME_attack9, boss2_frames_attack_pre_mg, NULL};
  279 
  280 
  281 // Loop this
  282 mframe_t boss2_frames_attack_mg [] =
  283 {
  284         ai_charge,      1,      Boss2MachineGun,
  285         ai_charge,      1,      Boss2MachineGun,
  286         ai_charge,      1,      Boss2MachineGun,
  287         ai_charge,      1,      Boss2MachineGun,
  288         ai_charge,      1,      Boss2MachineGun,
  289         ai_charge,      1,      boss2_reattack_mg
  290 };
  291 mmove_t boss2_move_attack_mg = {FRAME_attack10, FRAME_attack15, boss2_frames_attack_mg, NULL};
  292 
  293 mframe_t boss2_frames_attack_post_mg [] =
  294 {
  295         ai_charge,      1,      NULL,
  296         ai_charge,      1,      NULL,
  297         ai_charge,      1,      NULL,
  298         ai_charge,      1,      NULL
  299 };
  300 mmove_t boss2_move_attack_post_mg = {FRAME_attack16, FRAME_attack19, boss2_frames_attack_post_mg, boss2_run};
  301 
  302 mframe_t boss2_frames_attack_rocket [] =
  303 {
  304         ai_charge,      1,      NULL,
  305         ai_charge,      1,      NULL,
  306         ai_charge,      1,      NULL,
  307         ai_charge,      1,      NULL,
  308         ai_charge,      1,      NULL,
  309         ai_charge,      1,      NULL,
  310         ai_charge,      1,      NULL,
  311         ai_charge,      1,      NULL,
  312         ai_charge,      1,      NULL,
  313         ai_charge,      1,      NULL,
  314         ai_charge,      1,      NULL,
  315         ai_charge,      1,      NULL,
  316         ai_move,        -20,    Boss2Rocket,
  317         ai_charge,      1,      NULL,
  318         ai_charge,      1,      NULL,
  319         ai_charge,      1,      NULL,
  320         ai_charge,      1,      NULL,
  321         ai_charge,      1,      NULL,
  322         ai_charge,      1,      NULL,
  323         ai_charge,      1,      NULL,
  324         ai_charge,      1,      NULL
  325 };
  326 mmove_t boss2_move_attack_rocket = {FRAME_attack20, FRAME_attack40, boss2_frames_attack_rocket, boss2_run};
  327 
  328 mframe_t boss2_frames_pain_heavy [] =
  329 {
  330         ai_move,        0,      NULL,
  331         ai_move,        0,      NULL,
  332         ai_move,        0,      NULL,
  333         ai_move,        0,      NULL,
  334         ai_move,        0,      NULL,
  335         ai_move,        0,      NULL,
  336         ai_move,        0,      NULL,
  337         ai_move,        0,      NULL,
  338         ai_move,        0,      NULL,
  339         ai_move,        0,      NULL,
  340         ai_move,        0,      NULL,
  341         ai_move,        0,      NULL,
  342         ai_move,        0,      NULL,
  343         ai_move,        0,      NULL,
  344         ai_move,        0,      NULL,
  345         ai_move,        0,      NULL,
  346         ai_move,        0,      NULL,
  347         ai_move,        0,      NULL
  348 };
  349 mmove_t boss2_move_pain_heavy = {FRAME_pain2, FRAME_pain19, boss2_frames_pain_heavy, boss2_run};
  350 
  351 mframe_t boss2_frames_pain_light [] =
  352 {
  353         ai_move,        0,      NULL,
  354         ai_move,        0,      NULL,
  355         ai_move,        0,      NULL,
  356         ai_move,        0,      NULL
  357 };
  358 mmove_t boss2_move_pain_light = {FRAME_pain20, FRAME_pain23, boss2_frames_pain_light, boss2_run};
  359 
  360 mframe_t boss2_frames_death [] =
  361 {
  362         ai_move,        0,      NULL,
  363         ai_move,        0,      NULL,
  364         ai_move,        0,      NULL,
  365         ai_move,        0,      NULL,
  366         ai_move,        0,      NULL,
  367         ai_move,        0,      NULL,
  368         ai_move,        0,      NULL,
  369         ai_move,        0,      NULL,
  370         ai_move,        0,      NULL,
  371         ai_move,        0,      NULL,
  372         ai_move,        0,      NULL,
  373         ai_move,        0,      NULL,
  374         ai_move,        0,      NULL,
  375         ai_move,        0,      NULL,
  376         ai_move,        0,      NULL,
  377         ai_move,        0,      NULL,
  378         ai_move,        0,      NULL,
  379         ai_move,        0,      NULL,
  380         ai_move,        0,      NULL,
  381         ai_move,        0,      NULL,
  382         ai_move,        0,      NULL,
  383         ai_move,        0,      NULL,
  384         ai_move,        0,      NULL,
  385         ai_move,        0,      NULL,
  386         ai_move,        0,      NULL,
  387         ai_move,        0,      NULL,
  388         ai_move,        0,      NULL,
  389         ai_move,        0,      NULL,
  390         ai_move,        0,      NULL,
  391         ai_move,        0,      NULL,
  392         ai_move,        0,      NULL,
  393         ai_move,        0,      NULL,
  394         ai_move,        0,      NULL,
  395         ai_move,        0,      NULL,
  396         ai_move,        0,      NULL,
  397         ai_move,        0,      NULL,
  398         ai_move,        0,      NULL,
  399         ai_move,        0,      NULL,
  400         ai_move,        0,      NULL,
  401         ai_move,        0,      NULL,
  402         ai_move,        0,      NULL,
  403         ai_move,        0,      NULL,
  404         ai_move,        0,      NULL,
  405         ai_move,        0,      NULL,
  406         ai_move,        0,      NULL,
  407         ai_move,        0,      NULL,
  408         ai_move,        0,      NULL,
  409         ai_move,        0,      NULL,
  410         ai_move,        0,      BossExplode
  411 };
  412 mmove_t boss2_move_death = {FRAME_death2, FRAME_death50, boss2_frames_death, boss2_dead};
  413 
  414 void boss2_stand (edict_t *self)
  415 {
  416                 self->monsterinfo.currentmove = &boss2_move_stand;
  417 }
  418 
  419 void boss2_run (edict_t *self)
  420 {
  421         if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  422                 self->monsterinfo.currentmove = &boss2_move_stand;
  423         else
  424                 self->monsterinfo.currentmove = &boss2_move_run;
  425 }
  426 
  427 void boss2_walk (edict_t *self)
  428 {
  429         self->monsterinfo.currentmove = &boss2_move_walk;
  430 }
  431 
  432 void boss2_attack (edict_t *self)
  433 {
  434         vec3_t  vec;
  435         float   range;
  436 
  437         VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
  438         range = VectorLength (vec);
  439         
  440         if (range <= 125)
  441         {
  442                 self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
  443         }
  444         else 
  445         {
  446                 if (random() <= 0.6)
  447                         self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
  448                 else
  449                         self->monsterinfo.currentmove = &boss2_move_attack_rocket;
  450         }
  451 }
  452 
  453 void boss2_attack_mg (edict_t *self)
  454 {
  455         self->monsterinfo.currentmove = &boss2_move_attack_mg;
  456 }
  457 
  458 void boss2_reattack_mg (edict_t *self)
  459 {
  460         if ( infront(self, self->enemy) )
  461                 if (random() <= 0.7)
  462                         self->monsterinfo.currentmove = &boss2_move_attack_mg;
  463                 else
  464                         self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
  465         else
  466                 self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
  467 }
  468 
  469 
  470 void boss2_pain (edict_t *self, edict_t *other, float kick, int damage)
  471 {
  472         if (self->health < (self->max_health / 2))
  473                 self->s.skinnum = 1;
  474 
  475         if (level.time < self->pain_debounce_time)
  476                 return;
  477 
  478         self->pain_debounce_time = level.time + 3;
  479 // American wanted these at no attenuation
  480         if (damage < 10)
  481         {
  482                 gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0);
  483                 self->monsterinfo.currentmove = &boss2_move_pain_light;
  484         }
  485         else if (damage < 30)
  486         {
  487                 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0);
  488                 self->monsterinfo.currentmove = &boss2_move_pain_light;
  489         }
  490         else 
  491         {
  492                 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0);
  493                 self->monsterinfo.currentmove = &boss2_move_pain_heavy;
  494         }
  495 }
  496 
  497 void boss2_dead (edict_t *self)
  498 {
  499         VectorSet (self->mins, -56, -56, 0);
  500         VectorSet (self->maxs, 56, 56, 80);
  501         self->movetype = MOVETYPE_TOSS;
  502         self->svflags |= SVF_DEADMONSTER;
  503         self->nextthink = 0;
  504         gi.linkentity (self);
  505 }
  506 
  507 void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  508 {
  509         gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
  510         self->deadflag = DEAD_DEAD;
  511         self->takedamage = DAMAGE_NO;
  512         self->count = 0;
  513         self->monsterinfo.currentmove = &boss2_move_death;
  514 #if 0
515 int n; 516 517 self->s.sound = 0; 518 // check for gib 519 if (self->health <= self->gib_health) 520 { 521 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 522 for (n= 0; n < 2; n++) 523 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); 524 for (n= 0; n < 4; n++) 525 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 526 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 527 self->deadflag = DEAD_DEAD; 528 return; 529 } 530 531 if (self->deadflag == DEAD_DEAD) 532 return; 533 534 self->deadflag = DEAD_DEAD; 535 self->takedamage = DAMAGE_YES; 536 self->monsterinfo.currentmove = &boss2_move_death;
537 #endif 538 } 539 540 qboolean Boss2_CheckAttack (edict_t *self) 541 { 542 vec3_t spot1, spot2; 543 vec3_t temp; 544 float chance; 545 trace_t tr; 546 qboolean enemy_infront; 547 int enemy_range; 548 float enemy_yaw; 549 550 if (self->enemy->health > 0) 551 { 552 // see if any entities are in the way of the shot 553 VectorCopy (self->s.origin, spot1); 554 spot1[2] += self->viewheight; 555 VectorCopy (self->enemy->s.origin, spot2); 556 spot2[2] += self->enemy->viewheight; 557 558 tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA); 559 560 // do we have a clear shot? 561 if (tr.ent != self->enemy) 562 return false; 563 } 564 565 enemy_infront = infront(self, self->enemy); 566 enemy_range = range(self, self->enemy); 567 VectorSubtract (self->enemy->s.origin, self->s.origin, temp); 568 enemy_yaw = vectoyaw(temp); 569 570 self->ideal_yaw = enemy_yaw; 571 572 573 // melee attack 574 if (enemy_range == RANGE_MELEE) 575 { 576 if (self->monsterinfo.melee) 577 self->monsterinfo.attack_state = AS_MELEE; 578 else 579 self->monsterinfo.attack_state = AS_MISSILE; 580 return true; 581 } 582 583 // missile attack 584 if (!self->monsterinfo.attack) 585 return false; 586 587 if (level.time < self->monsterinfo.attack_finished) 588 return false; 589 590 if (enemy_range == RANGE_FAR) 591 return false; 592 593 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 594 { 595 chance = 0.4; 596 } 597 else if (enemy_range == RANGE_MELEE) 598 { 599 chance = 0.8; 600 } 601 else if (enemy_range == RANGE_NEAR) 602 { 603 chance = 0.8; 604 } 605 else if (enemy_range == RANGE_MID) 606 { 607 chance = 0.8; 608 } 609 else 610 { 611 return false; 612 } 613 614 if (random () < chance) 615 { 616 self->monsterinfo.attack_state = AS_MISSILE; 617 self->monsterinfo.attack_finished = level.time + 2*random(); 618 return true; 619 } 620 621 if (self->flags & FL_FLY) 622 { 623 if (random() < 0.3) 624 self->monsterinfo.attack_state = AS_SLIDING; 625 else 626 self->monsterinfo.attack_state = AS_STRAIGHT; 627 } 628 629 return false; 630 } 631 632 633 634 /*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight 635 */ 636 void SP_monster_boss2 (edict_t *self) 637 { 638 if (deathmatch->value) 639 { 640 G_FreeEdict (self); 641 return; 642 } 643 644 sound_pain1 = gi.soundindex ("bosshovr/bhvpain1.wav"); 645 sound_pain2 = gi.soundindex ("bosshovr/bhvpain2.wav"); 646 sound_pain3 = gi.soundindex ("bosshovr/bhvpain3.wav"); 647 sound_death = gi.soundindex ("bosshovr/bhvdeth1.wav"); 648 sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav"); 649 650 self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav"); 651 652 self->movetype = MOVETYPE_STEP; 653 self->solid = SOLID_BBOX; 654 self->s.modelindex = gi.modelindex ("models/monsters/boss2/tris.md2"); 655 VectorSet (self->mins, -56, -56, 0); 656 VectorSet (self->maxs, 56, 56, 80); 657 658 self->health = 2000; 659 self->gib_health = -200; 660 self->mass = 1000; 661 662 self->flags |= FL_IMMUNE_LASER; 663 664 self->pain = boss2_pain; 665 self->die = boss2_die; 666 667 self->monsterinfo.stand = boss2_stand; 668 self->monsterinfo.walk = boss2_walk; 669 self->monsterinfo.run = boss2_run; 670 self->monsterinfo.attack = boss2_attack; 671 self->monsterinfo.search = boss2_search; 672 self->monsterinfo.checkattack = Boss2_CheckAttack; 673 gi.linkentity (self); 674 675 self->monsterinfo.currentmove = &boss2_move_stand; 676 self->monsterinfo.scale = MODEL_SCALE; 677 678 flymonster_start (self); 679 } 680