1 /*
2 * Copyright (C) 1997-2001 Id Software, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * 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 along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59
17 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21 /*
22 *
23 * ============================================================================
24 * ==
25 *
26 * Makron -- Final Boss
27 *
28 * ====================
29 * =========================================================
30 */
31
32 #include "g_local.h"
33 #include "m_boss32.h"
34
35 qboolean visible(edict_t * self, edict_t * other);
36
37 void MakronRailgun(edict_t * self);
38 void MakronSaveloc(edict_t * self);
39 void MakronHyperblaster(edict_t * self);
40 void makron_step_left(edict_t * self);
41 void makron_step_right(edict_t * self);
42 void makronBFG (edict_t * self);
43 void makron_dead(edict_t * self);
44
45 static int sound_pain4;
46 static int sound_pain5;
47 static int sound_pain6;
48 static int sound_death;
49 static int sound_step_left;
50 static int sound_step_right;
51 static int sound_attack_bfg;
52 static int sound_brainsplorch;
53 static int sound_prerailgun;
54 static int sound_popup;
55 static int sound_taunt1;
56 static int sound_taunt2;
57 static int sound_taunt3;
58 static int sound_hit;
59
60 void
makron_taunt(edict_t * self)61 makron_taunt(edict_t * self)
62 {
63 float r;
64
65 r = random();
66 if (r <= 0.3)
67 gi.sound(self, CHAN_AUTO, sound_taunt1, 1, ATTN_NONE, 0);
68 else if (r <= 0.6)
69 gi.sound(self, CHAN_AUTO, sound_taunt2, 1, ATTN_NONE, 0);
70 else
71 gi.sound(self, CHAN_AUTO, sound_taunt3, 1, ATTN_NONE, 0);
72 }
73
74 //
75 /* stand */
76 //
77
78 mframe_t makron_frames_stand[] =
79 {
80 {
81 ai_stand, 0, NULL
82 },
83 {
84 ai_stand, 0, NULL
85 },
86 {
87 ai_stand, 0, NULL
88 },
89 {
90 ai_stand, 0, NULL
91 },
92 {
93 ai_stand, 0, NULL
94 },
95 {
96 ai_stand, 0, NULL
97 },
98 {
99 ai_stand, 0, NULL
100 },
101 {
102 ai_stand, 0, NULL
103 },
104 {
105 ai_stand, 0, NULL
106 },
107 {
108 ai_stand, 0, NULL
109 }, /* 10 */
110 {
111 ai_stand, 0, NULL
112 },
113 {
114 ai_stand, 0, NULL
115 },
116 {
117 ai_stand, 0, NULL
118 },
119 {
120 ai_stand, 0, NULL
121 },
122 {
123 ai_stand, 0, NULL
124 },
125 {
126 ai_stand, 0, NULL
127 },
128 {
129 ai_stand, 0, NULL
130 },
131 {
132 ai_stand, 0, NULL
133 },
134 {
135 ai_stand, 0, NULL
136 },
137 {
138 ai_stand, 0, NULL
139 }, /* 20 */
140 {
141 ai_stand, 0, NULL
142 },
143 {
144 ai_stand, 0, NULL
145 },
146 {
147 ai_stand, 0, NULL
148 },
149 {
150 ai_stand, 0, NULL
151 },
152 {
153 ai_stand, 0, NULL
154 },
155 {
156 ai_stand, 0, NULL
157 },
158 {
159 ai_stand, 0, NULL
160 },
161 {
162 ai_stand, 0, NULL
163 },
164 {
165 ai_stand, 0, NULL
166 },
167 {
168 ai_stand, 0, NULL
169 }, /* 30 */
170 {
171 ai_stand, 0, NULL
172 },
173 {
174 ai_stand, 0, NULL
175 },
176 {
177 ai_stand, 0, NULL
178 },
179 {
180 ai_stand, 0, NULL
181 },
182 {
183 ai_stand, 0, NULL
184 },
185 {
186 ai_stand, 0, NULL
187 },
188 {
189 ai_stand, 0, NULL
190 },
191 {
192 ai_stand, 0, NULL
193 },
194 {
195 ai_stand, 0, NULL
196 },
197 {
198 ai_stand, 0, NULL
199 }, /* 40 */
200 {
201 ai_stand, 0, NULL
202 },
203 {
204 ai_stand, 0, NULL
205 },
206 {
207 ai_stand, 0, NULL
208 },
209 {
210 ai_stand, 0, NULL
211 },
212 {
213 ai_stand, 0, NULL
214 },
215 {
216 ai_stand, 0, NULL
217 },
218 {
219 ai_stand, 0, NULL
220 },
221 {
222 ai_stand, 0, NULL
223 },
224 {
225 ai_stand, 0, NULL
226 },
227 {
228 ai_stand, 0, NULL
229 }, /* 50 */
230 {
231 ai_stand, 0, NULL
232 },
233 {
234 ai_stand, 0, NULL
235 },
236 {
237 ai_stand, 0, NULL
238 },
239 {
240 ai_stand, 0, NULL
241 },
242 {
243 ai_stand, 0, NULL
244 },
245 {
246 ai_stand, 0, NULL
247 },
248 {
249 ai_stand, 0, NULL
250 },
251 {
252 ai_stand, 0, NULL
253 },
254 {
255 ai_stand, 0, NULL
256 },
257 {
258 ai_stand, 0, NULL
259 } /* 60 */
260 };
261 mmove_t makron_move_stand = {FRAME_stand201, FRAME_stand260, makron_frames_stand, NULL};
262
263 void
makron_stand(edict_t * self)264 makron_stand(edict_t * self)
265 {
266 self->monsterinfo.currentmove = &makron_move_stand;
267 }
268
269 mframe_t makron_frames_run[] =
270 {
271 {ai_run, 3, makron_step_left},
272 {ai_run, 12, NULL},
273 {ai_run, 8, NULL},
274 {ai_run, 8, NULL},
275 {ai_run, 8, makron_step_right},
276 {ai_run, 6, NULL},
277 {ai_run, 12, NULL},
278 {ai_run, 9, NULL},
279 {ai_run, 6, NULL},
280 {ai_run, 12, NULL}
281 };
282 mmove_t makron_move_run = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
283
284 void
makron_hit(edict_t * self)285 makron_hit(edict_t * self)
286 {
287 gi.sound(self, CHAN_AUTO, sound_hit, 1, ATTN_NONE, 0);
288 }
289
290 void
makron_popup(edict_t * self)291 makron_popup(edict_t * self)
292 {
293 gi.sound(self, CHAN_BODY, sound_popup, 1, ATTN_NONE, 0);
294 }
295
296 void
makron_step_left(edict_t * self)297 makron_step_left(edict_t * self)
298 {
299 gi.sound(self, CHAN_BODY, sound_step_left, 1, ATTN_NORM, 0);
300 }
301
302 void
makron_step_right(edict_t * self)303 makron_step_right(edict_t * self)
304 {
305 gi.sound(self, CHAN_BODY, sound_step_right, 1, ATTN_NORM, 0);
306 }
307
308 void
makron_brainsplorch(edict_t * self)309 makron_brainsplorch(edict_t * self)
310 {
311 gi.sound(self, CHAN_VOICE, sound_brainsplorch, 1, ATTN_NORM, 0);
312 }
313
314 void
makron_prerailgun(edict_t * self)315 makron_prerailgun(edict_t * self)
316 {
317 gi.sound(self, CHAN_WEAPON, sound_prerailgun, 1, ATTN_NORM, 0);
318 }
319
320
321 mframe_t makron_frames_walk[] =
322 {
323 {ai_walk, 3, makron_step_left},
324 {ai_walk, 12, NULL},
325 {ai_walk, 8, NULL},
326 {ai_walk, 8, NULL},
327 {ai_walk, 8, makron_step_right},
328 {ai_walk, 6, NULL},
329 {ai_walk, 12, NULL},
330 {ai_walk, 9, NULL},
331 {ai_walk, 6, NULL},
332 {ai_walk, 12, NULL}
333 };
334 mmove_t makron_move_walk = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
335
336 void
makron_walk(edict_t * self)337 makron_walk(edict_t * self)
338 {
339 self->monsterinfo.currentmove = &makron_move_walk;
340 }
341
342 void
makron_run(edict_t * self)343 makron_run(edict_t * self)
344 {
345 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
346 self->monsterinfo.currentmove = &makron_move_stand;
347 else
348 self->monsterinfo.currentmove = &makron_move_run;
349 }
350
351 mframe_t makron_frames_pain6[] =
352 {
353 {ai_move, 0, NULL},
354 {ai_move, 0, NULL},
355 {ai_move, 0, NULL},
356 {ai_move, 0, NULL},
357 {ai_move, 0, NULL},
358 {ai_move, 0, NULL},
359 {ai_move, 0, NULL},
360 {ai_move, 0, NULL},
361 {ai_move, 0, NULL},
362 {ai_move, 0, NULL}, /* 10 */
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, makron_popup},
369 {ai_move, 0, NULL},
370 {ai_move, 0, NULL},
371 {ai_move, 0, NULL},
372 {ai_move, 0, NULL}, /* 20 */
373 {ai_move, 0, NULL},
374 {ai_move, 0, NULL},
375 {ai_move, 0, NULL},
376 {ai_move, 0, makron_taunt},
377 {ai_move, 0, NULL},
378 {ai_move, 0, NULL},
379 {ai_move, 0, NULL}
380 };
381 mmove_t makron_move_pain6 = {FRAME_pain601, FRAME_pain627, makron_frames_pain6, makron_run};
382
383 mframe_t makron_frames_pain5[] =
384 {
385 {ai_move, 0, NULL},
386 {ai_move, 0, NULL},
387 {ai_move, 0, NULL},
388 {ai_move, 0, NULL}
389 };
390 mmove_t makron_move_pain5 = {FRAME_pain501, FRAME_pain504, makron_frames_pain5, makron_run};
391
392 mframe_t makron_frames_pain4[] =
393 {
394 {ai_move, 0, NULL},
395 {ai_move, 0, NULL},
396 {ai_move, 0, NULL},
397 {ai_move, 0, NULL}
398 };
399 mmove_t makron_move_pain4 = {FRAME_pain401, FRAME_pain404, makron_frames_pain4, makron_run};
400
401 mframe_t makron_frames_death2[] =
402 {
403 {ai_move, -15, NULL},
404 {ai_move, 3, NULL},
405 {ai_move, -12, NULL},
406 {ai_move, 0, makron_step_left},
407 {ai_move, 0, NULL},
408 {ai_move, 0, NULL},
409 {ai_move, 0, NULL},
410 {ai_move, 0, NULL},
411 {ai_move, 0, NULL},
412 {ai_move, 0, NULL}, /* 10 */
413 {ai_move, 0, NULL},
414 {ai_move, 0, NULL},
415 {ai_move, 0, NULL},
416 {ai_move, 0, NULL},
417 {ai_move, 0, NULL},
418 {ai_move, 11, NULL},
419 {ai_move, 12, NULL},
420 {ai_move, 11, makron_step_right},
421 {ai_move, 0, NULL},
422 {ai_move, 0, NULL}, /* 20 */
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}, /* 30 */
433 {ai_move, 0, NULL},
434 {ai_move, 0, NULL},
435 {ai_move, 0, NULL},
436 {ai_move, 5, NULL},
437 {ai_move, 7, NULL},
438 {ai_move, 6, makron_step_left},
439 {ai_move, 0, NULL},
440 {ai_move, 0, NULL},
441 {ai_move, -1, NULL},
442 {ai_move, 2, NULL}, /* 40 */
443 {ai_move, 0, NULL},
444 {ai_move, 0, NULL},
445 {ai_move, 0, NULL},
446 {ai_move, 0, NULL},
447 {ai_move, 0, NULL},
448 {ai_move, 0, NULL},
449 {ai_move, 0, NULL},
450 {ai_move, 0, NULL},
451 {ai_move, 0, NULL},
452 {ai_move, 0, NULL}, /* 50 */
453 {ai_move, 0, NULL},
454 {ai_move, 0, NULL},
455 {ai_move, 0, NULL},
456 {ai_move, -6, NULL},
457 {ai_move, -4, NULL},
458 {ai_move, -6, makron_step_right},
459 {ai_move, -4, NULL},
460 {ai_move, -4, makron_step_left},
461 {ai_move, 0, NULL},
462 {ai_move, 0, NULL}, /* 60 */
463 {ai_move, 0, NULL},
464 {ai_move, 0, NULL},
465 {ai_move, -2, NULL},
466 {ai_move, -5, NULL},
467 {ai_move, -3, makron_step_right},
468 {ai_move, -8, NULL},
469 {ai_move, -3, makron_step_left},
470 {ai_move, -7, NULL},
471 {ai_move, -4, NULL},
472 {ai_move, -4, makron_step_right}, /* 70 */
473 {ai_move, -6, NULL},
474 {ai_move, -7, NULL},
475 {ai_move, 0, makron_step_left},
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}, /* 80 */
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, -2, NULL},
489 {ai_move, 0, NULL},
490 {ai_move, 0, NULL},
491 {ai_move, 2, NULL},
492 {ai_move, 0, NULL}, /* 90 */
493 {ai_move, 27, makron_hit},
494 {ai_move, 26, NULL},
495 {ai_move, 0, makron_brainsplorch},
496 {ai_move, 0, NULL},
497 {ai_move, 0, NULL} /* 95 */
498 };
499 mmove_t makron_move_death2 = {FRAME_death201, FRAME_death295, makron_frames_death2, makron_dead};
500
501 mframe_t makron_frames_death3[] =
502 {
503 {ai_move, 0, NULL},
504 {ai_move, 0, NULL},
505 {ai_move, 0, NULL},
506 {ai_move, 0, NULL},
507 {ai_move, 0, NULL},
508 {ai_move, 0, NULL},
509 {ai_move, 0, NULL},
510 {ai_move, 0, NULL},
511 {ai_move, 0, NULL},
512 {ai_move, 0, NULL},
513 {ai_move, 0, NULL},
514 {ai_move, 0, NULL},
515 {ai_move, 0, NULL},
516 {ai_move, 0, NULL},
517 {ai_move, 0, NULL},
518 {ai_move, 0, NULL},
519 {ai_move, 0, NULL},
520 {ai_move, 0, NULL},
521 {ai_move, 0, NULL},
522 {ai_move, 0, NULL}
523 };
524 mmove_t makron_move_death3 = {FRAME_death301, FRAME_death320, makron_frames_death3, NULL};
525
526 mframe_t makron_frames_sight[] =
527 {
528 {ai_move, 0, NULL},
529 {ai_move, 0, NULL},
530 {ai_move, 0, NULL},
531 {ai_move, 0, NULL},
532 {ai_move, 0, NULL},
533 {ai_move, 0, NULL},
534 {ai_move, 0, NULL},
535 {ai_move, 0, NULL},
536 {ai_move, 0, NULL},
537 {ai_move, 0, NULL},
538 {ai_move, 0, NULL},
539 {ai_move, 0, NULL},
540 {ai_move, 0, NULL}
541 };
542 mmove_t makron_move_sight = {FRAME_active01, FRAME_active13, makron_frames_sight, makron_run};
543
544 void
makronBFG(edict_t * self)545 makronBFG(edict_t * self)
546 {
547 vec3_t forward, right;
548 vec3_t start;
549 vec3_t dir;
550 vec3_t vec;
551
552 AngleVectors(self->s.angles, forward, right, NULL);
553 G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_MAKRON_BFG], forward, right, start);
554
555 VectorCopy(self->enemy->s.origin, vec);
556 vec[2] += self->enemy->viewheight;
557 VectorSubtract(vec, start, dir);
558 VectorNormalize(dir);
559 gi.sound(self, CHAN_VOICE, sound_attack_bfg, 1, ATTN_NORM, 0);
560 monster_fire_bfg(self, start, dir, 50, 300, 100, 300, MZ2_MAKRON_BFG);
561 }
562
563
564 mframe_t makron_frames_attack3[] =
565 {
566 {ai_charge, 0, NULL},
567 {ai_charge, 0, NULL},
568 {ai_charge, 0, NULL},
569 {ai_charge, 0, makronBFG}, /* FIXME: BFG Attack here */
570 {ai_move, 0, NULL},
571 {ai_move, 0, NULL},
572 {ai_move, 0, NULL},
573 {ai_move, 0, NULL}
574 };
575 mmove_t makron_move_attack3 = {FRAME_attak301, FRAME_attak308, makron_frames_attack3, makron_run};
576
577 mframe_t makron_frames_attack4[] =
578 {
579 {ai_charge, 0, NULL},
580 {ai_charge, 0, NULL},
581 {ai_charge, 0, NULL},
582 {ai_charge, 0, NULL},
583 {ai_move, 0, MakronHyperblaster}, /* fire */
584 {ai_move, 0, MakronHyperblaster}, /* fire */
585 {ai_move, 0, MakronHyperblaster}, /* fire */
586 {ai_move, 0, MakronHyperblaster}, /* fire */
587 {ai_move, 0, MakronHyperblaster}, /* fire */
588 {ai_move, 0, MakronHyperblaster}, /* fire */
589 {ai_move, 0, MakronHyperblaster}, /* fire */
590 {ai_move, 0, MakronHyperblaster}, /* fire */
591 {ai_move, 0, MakronHyperblaster}, /* fire */
592 {ai_move, 0, MakronHyperblaster}, /* fire */
593 {ai_move, 0, MakronHyperblaster}, /* fire */
594 {ai_move, 0, MakronHyperblaster}, /* fire */
595 {ai_move, 0, MakronHyperblaster}, /* fire */
596 {ai_move, 0, MakronHyperblaster}, /* fire */
597 {ai_move, 0, MakronHyperblaster}, /* fire */
598 {ai_move, 0, MakronHyperblaster}, /* fire */
599 {ai_move, 0, MakronHyperblaster}, /* fire */
600 {ai_move, 0, NULL},
601 {ai_move, 0, NULL},
602 {ai_move, 0, NULL},
603 {ai_move, 0, NULL},
604 {ai_move, 0, NULL}
605 };
606 mmove_t makron_move_attack4 = {FRAME_attak401, FRAME_attak426, makron_frames_attack4, makron_run};
607
608 mframe_t makron_frames_attack5[] =
609 {
610 {ai_charge, 0, makron_prerailgun},
611 {ai_charge, 0, NULL},
612 {ai_charge, 0, NULL},
613 {ai_charge, 0, NULL},
614 {ai_charge, 0, NULL},
615 {ai_charge, 0, NULL},
616 {ai_charge, 0, NULL},
617 {ai_charge, 0, MakronSaveloc},
618 {ai_move, 0, MakronRailgun}, /* Fire railgun */
619 {ai_move, 0, NULL},
620 {ai_move, 0, NULL},
621 {ai_move, 0, NULL},
622 {ai_move, 0, NULL},
623 {ai_move, 0, NULL},
624 {ai_move, 0, NULL},
625 {ai_move, 0, NULL}
626 };
627 mmove_t makron_move_attack5 = {FRAME_attak501, FRAME_attak516, makron_frames_attack5, makron_run};
628
629 void
MakronSaveloc(edict_t * self)630 MakronSaveloc(edict_t * self)
631 {
632 VectorCopy(self->enemy->s.origin, self->pos1); /* save for aiming the
633 * shot */
634 self->pos1[2] += self->enemy->viewheight;
635 }
636
637 /* FIXME: He's not firing from the proper Z */
638 void
MakronRailgun(edict_t * self)639 MakronRailgun(edict_t * self)
640 {
641 vec3_t start;
642 vec3_t dir;
643 vec3_t forward, right;
644
645 AngleVectors(self->s.angles, forward, right, NULL);
646 G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_MAKRON_RAILGUN_1], forward, right, start);
647
648 /* calc direction to where we targted */
649 VectorSubtract(self->pos1, start, dir);
650 VectorNormalize(dir);
651
652 monster_fire_railgun(self, start, dir, 50, 100, MZ2_MAKRON_RAILGUN_1);
653 }
654
655 /* FIXME: This is all wrong. He's not firing at the proper angles. */
656 void
MakronHyperblaster(edict_t * self)657 MakronHyperblaster(edict_t * self)
658 {
659 vec3_t dir;
660 vec3_t vec;
661 vec3_t start;
662 vec3_t forward, right;
663 int flash_number;
664
665 flash_number = MZ2_MAKRON_BLASTER_1 + (self->s.frame - FRAME_attak405);
666
667 AngleVectors(self->s.angles, forward, right, NULL);
668 G_ProjectSource(self->s.origin, monster_flash_offset[flash_number], forward, right, start);
669
670 if (self->enemy) {
671 VectorCopy(self->enemy->s.origin, vec);
672 vec[2] += self->enemy->viewheight;
673 VectorSubtract(vec, start, vec);
674 vectoangles(vec, vec);
675 dir[0] = vec[0];
676 } else {
677 dir[0] = 0;
678 }
679 if (self->s.frame <= FRAME_attak413)
680 dir[1] = self->s.angles[1] - 10 * (self->s.frame - FRAME_attak413);
681 else
682 dir[1] = self->s.angles[1] + 10 * (self->s.frame - FRAME_attak421);
683 dir[2] = 0;
684
685 AngleVectors(dir, forward, NULL, NULL);
686
687 monster_fire_blaster(self, start, forward, 15, 1000, MZ2_MAKRON_BLASTER_1, EF_BLASTER);
688 }
689
690
691 void
makron_pain(edict_t * self,edict_t * other,float kick,int damage)692 makron_pain(edict_t * self, edict_t * other, float kick, int damage)
693 {
694
695 if (self->health < (self->max_health / 2))
696 self->s.skinnum = 1;
697
698 if (level.time < self->pain_debounce_time)
699 return;
700
701 /* Lessen the chance of him going into his pain frames */
702 if (damage <= 25)
703 if (random() < 0.2)
704 return;
705
706 self->pain_debounce_time = level.time + 3;
707 if (skill->value == 3)
708 return; /* no pain anims in nightmare */
709
710
711 if (damage <= 40) {
712 gi.sound(self, CHAN_VOICE, sound_pain4, 1, ATTN_NONE, 0);
713 self->monsterinfo.currentmove = &makron_move_pain4;
714 } else if (damage <= 110) {
715 gi.sound(self, CHAN_VOICE, sound_pain5, 1, ATTN_NONE, 0);
716 self->monsterinfo.currentmove = &makron_move_pain5;
717 } else {
718 if (damage <= 150) {
719 if (random() <= 0.45) {
720 gi.sound(self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE, 0);
721 self->monsterinfo.currentmove = &makron_move_pain6;
722 } else if (random() <= 0.35) {
723 gi.sound(self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE, 0);
724 self->monsterinfo.currentmove = &makron_move_pain6;
725 }
726 }
727 }
728 }
729
730 void
makron_sight(edict_t * self,edict_t * other)731 makron_sight(edict_t * self, edict_t * other)
732 {
733 self->monsterinfo.currentmove = &makron_move_sight;
734 }
735
736 void
makron_attack(edict_t * self)737 makron_attack(edict_t * self)
738 {
739 vec3_t vec;
740 float range;
741 float r;
742
743 r = random();
744
745 VectorSubtract(self->enemy->s.origin, self->s.origin, vec);
746 range = VectorLength(vec);
747
748
749 if (r <= 0.3)
750 self->monsterinfo.currentmove = &makron_move_attack3;
751 else if (r <= 0.6)
752 self->monsterinfo.currentmove = &makron_move_attack4;
753 else
754 self->monsterinfo.currentmove = &makron_move_attack5;
755 }
756
757 /*
758 * --- Makron Torso. This needs to be spawned in ---
759 */
760
761 void
makron_torso_think(edict_t * self)762 makron_torso_think(edict_t * self)
763 {
764 if (++self->s.frame < 365)
765 self->nextthink = level.time + FRAMETIME;
766 else {
767 self->s.frame = 346;
768 self->nextthink = level.time + FRAMETIME;
769 }
770 }
771
772 void
makron_torso(edict_t * ent)773 makron_torso(edict_t * ent)
774 {
775 ent->movetype = MOVETYPE_NONE;
776 ent->solid = SOLID_NOT;
777 VectorSet(ent->mins, -8, -8, 0);
778 VectorSet(ent->maxs, 8, 8, 8);
779 ent->s.frame = 346;
780 ent->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2");
781 ent->think = makron_torso_think;
782 ent->nextthink = level.time + 2 * FRAMETIME;
783 ent->s.sound = gi.soundindex("makron/spine.wav");
784 gi.linkentity(ent);
785 }
786
787
788 //
789 /* death */
790 //
791
792 void
makron_dead(edict_t * self)793 makron_dead(edict_t * self)
794 {
795 VectorSet(self->mins, -60, -60, 0);
796 VectorSet(self->maxs, 60, 60, 72);
797 self->movetype = MOVETYPE_TOSS;
798 self->svflags |= SVF_DEADMONSTER;
799 self->nextthink = 0;
800 gi.linkentity(self);
801 }
802
803
804 void
makron_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)805 makron_die(edict_t * self, edict_t * inflictor, edict_t * attacker, int damage, vec3_t point)
806 {
807 edict_t *tempent;
808
809 int n;
810
811 self->s.sound = 0;
812 /* check for gib */
813 if (self->health <= self->gib_health) {
814 gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
815 for (n = 0; n < 1 /* 4 */ ; n++)
816 ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
817 for (n = 0; n < 4; n++)
818 ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
819 ThrowHead(self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
820 self->deadflag = DEAD_DEAD;
821 return;
822 }
823 if (self->deadflag == DEAD_DEAD)
824 return;
825
826 /* regular death */
827 gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
828 self->deadflag = DEAD_DEAD;
829 self->takedamage = DAMAGE_YES;
830
831 tempent = G_Spawn();
832 VectorCopy(self->s.origin, tempent->s.origin);
833 VectorCopy(self->s.angles, tempent->s.angles);
834 tempent->s.origin[1] -= 84;
835 makron_torso(tempent);
836
837 self->monsterinfo.currentmove = &makron_move_death2;
838
839 }
840
841 qboolean
Makron_CheckAttack(edict_t * self)842 Makron_CheckAttack(edict_t * self)
843 {
844 vec3_t spot1 , spot2;
845 vec3_t temp;
846 float chance;
847 trace_t tr;
848 qboolean enemy_infront;
849 int enemy_range;
850 float enemy_yaw;
851
852 if (self->enemy->health > 0) {
853 /* see if any entities are in the way of the shot */
854 VectorCopy(self->s.origin, spot1);
855 spot1[2] += self->viewheight;
856 VectorCopy(self->enemy->s.origin, spot2);
857 spot2[2] += self->enemy->viewheight;
858
859 tr = gi.trace(spot1, NULL, NULL, spot2, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA);
860
861 /* do we have a clear shot? */
862 if (tr.ent != self->enemy)
863 return false;
864 }
865 enemy_infront = infront(self, self->enemy);
866 enemy_range = range(self, self->enemy);
867 VectorSubtract(self->enemy->s.origin, self->s.origin, temp);
868 enemy_yaw = vectoyaw(temp);
869
870 self->ideal_yaw = enemy_yaw;
871
872
873 /* melee attack */
874 if (enemy_range == RANGE_MELEE) {
875 if (self->monsterinfo.melee)
876 self->monsterinfo.attack_state = AS_MELEE;
877 else
878 self->monsterinfo.attack_state = AS_MISSILE;
879 return true;
880 }
881 /* missile attack */
882 if (!self->monsterinfo.attack)
883 return false;
884
885 if (level.time < self->monsterinfo.attack_finished)
886 return false;
887
888 if (enemy_range == RANGE_FAR)
889 return false;
890
891 if (self->monsterinfo.aiflags & AI_STAND_GROUND) {
892 chance = 0.4;
893 } else if (enemy_range == RANGE_MELEE) {
894 chance = 0.8;
895 } else if (enemy_range == RANGE_NEAR) {
896 chance = 0.4;
897 } else if (enemy_range == RANGE_MID) {
898 chance = 0.2;
899 } else {
900 return false;
901 }
902
903 if (random() < chance) {
904 self->monsterinfo.attack_state = AS_MISSILE;
905 self->monsterinfo.attack_finished = level.time + 2 * random();
906 return true;
907 }
908 if (self->flags & FL_FLY) {
909 if (random() < 0.3)
910 self->monsterinfo.attack_state = AS_SLIDING;
911 else
912 self->monsterinfo.attack_state = AS_STRAIGHT;
913 }
914 return false;
915 }
916
917
918 //
919 /* monster_makron */
920 //
921
922 void
MakronPrecache(void)923 MakronPrecache(void)
924 {
925 sound_pain4 = gi.soundindex("makron/pain3.wav");
926 sound_pain5 = gi.soundindex("makron/pain2.wav");
927 sound_pain6 = gi.soundindex("makron/pain1.wav");
928 sound_death = gi.soundindex("makron/death.wav");
929 sound_step_left = gi.soundindex("makron/step1.wav");
930 sound_step_right = gi.soundindex("makron/step2.wav");
931 sound_attack_bfg = gi.soundindex("makron/bfg_fire.wav");
932 sound_brainsplorch = gi.soundindex("makron/brain1.wav");
933 sound_prerailgun = gi.soundindex("makron/rail_up.wav");
934 sound_popup = gi.soundindex("makron/popup.wav");
935 sound_taunt1 = gi.soundindex("makron/voice4.wav");
936 sound_taunt2 = gi.soundindex("makron/voice3.wav");
937 sound_taunt3 = gi.soundindex("makron/voice.wav");
938 sound_hit = gi.soundindex("makron/bhit.wav");
939
940 gi.modelindex("models/monsters/boss3/rider/tris.md2");
941 }
942
943 /*
944 * QUAKED monster_makron (1 .5 0) (-30 -30 0) (30 30 90) Ambush Trigger_Spawn
945 * Sight
946 */
947 void
SP_monster_makron(edict_t * self)948 SP_monster_makron(edict_t * self)
949 {
950 if (deathmatch->value) {
951 G_FreeEdict(self);
952 return;
953 }
954 MakronPrecache();
955
956 self->movetype = MOVETYPE_STEP;
957 self->solid = SOLID_BBOX;
958 self->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2");
959 VectorSet(self->mins, -30, -30, 0);
960 VectorSet(self->maxs, 30, 30, 90);
961
962 self->health = 3000;
963 self->gib_health = -2000;
964 self->mass = 500;
965
966 self->pain = makron_pain;
967 self->die = makron_die;
968 self->monsterinfo.stand = makron_stand;
969 self->monsterinfo.walk = makron_walk;
970 self->monsterinfo.run = makron_run;
971 self->monsterinfo.dodge = NULL;
972 self->monsterinfo.attack = makron_attack;
973 self->monsterinfo.melee = NULL;
974 self->monsterinfo.sight = makron_sight;
975 self->monsterinfo.checkattack = Makron_CheckAttack;
976
977 gi.linkentity(self);
978
979 /* self->monsterinfo.currentmove = &makron_move_stand; */
980 self->monsterinfo.currentmove = &makron_move_sight;
981 self->monsterinfo.scale = MODEL_SCALE;
982
983 walkmonster_start(self);
984 }
985
986
987 /*
988 * ================= MakronSpawn
989 *
990 * =================
991 */
992 void
MakronSpawn(edict_t * self)993 MakronSpawn(edict_t * self)
994 {
995 vec3_t vec;
996 edict_t *player;
997
998 SP_monster_makron(self);
999
1000 /* jump at player */
1001 player = level.sight_client;
1002 if (!player)
1003 return;
1004
1005 VectorSubtract(player->s.origin, self->s.origin, vec);
1006 self->s.angles[YAW] = vectoyaw(vec);
1007 VectorNormalize(vec);
1008 VectorMA(vec3_origin, 400, vec, self->velocity);
1009 self->velocity[2] = 200;
1010 self->groundentity = NULL;
1011 }
1012
1013 /*
1014 * ================= MakronToss
1015 *
1016 * Jorg is just about dead, so set up to launch Makron out =================
1017 */
1018 void
MakronToss(edict_t * self)1019 MakronToss(edict_t * self)
1020 {
1021 edict_t *ent;
1022
1023 ent = G_Spawn();
1024 ent->nextthink = level.time + 0.8;
1025 ent->think = MakronSpawn;
1026 ent->target = self->target;
1027 VectorCopy(self->s.origin, ent->s.origin);
1028 }
1029