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