Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

m_boss2.c (16533B)


      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 }