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