1 #include "g_local.h"
2 #include "z_anim.h"
3 
4 #include "z_boss.h"
5 
6 static int	sound_pain1;
7 static int	sound_pain2;
8 static int	sound_pain3;
9 static int	sound_die1;
10 static int	sound_die2;
11 static int	sound_hookimpact;
12 static int	sound_sight;
13 static int	sound_hooklaunch;
14 static int	sound_hookfly;
15 static int	sound_swing;
16 static int	sound_idle1;
17 static int	sound_idle2;
18 static int	sound_walk;
19 static int	sound_raisegun;
20 static int	sound_lowergun;
21 static int  sound_switchattacks;
22 static int  sound_plamsaballfly;
23 static int  sound_plamsaballexplode;
24 static int  sound_plamsaballfire;
25 static int  sound_taunt1;
26 static int  sound_taunt2;
27 static int  sound_taunt3;
28 
29 
30 void fire_empnuke(edict_t	*ent, vec3_t center, int radius);
31 void SV_AddGravity (edict_t *ent);
32 
33 
34 void zboss_stand (edict_t *self);
35 void zboss_run (edict_t *self);
36 void zboss_run2 (edict_t *self);
37 void zboss_walk (edict_t *self);
38 void zboss_walk2(edict_t *self);
39 void zboss_chooseNextAttack(edict_t *self);
40 void zboss_reelInGraaple(edict_t *self);
41 void zboss_posthook(edict_t *self);
42 void HookDragThink (edict_t *self);
43 void zboss_attack (edict_t *self);
44 
45 
zboss_walksound(edict_t * self)46 void zboss_walksound (edict_t *self)
47 {
48 	gi.sound (self, CHAN_BODY, sound_walk, 1, ATTN_NORM, 0);
49 }
50 
51 
zboss_sight(edict_t * self,edict_t * other)52 void zboss_sight (edict_t *self, edict_t *other)
53 {
54 	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
55 }
56 
57 
possibleBossTaunt(edict_t * self)58 void possibleBossTaunt(edict_t *self)
59 {
60 	float r = random();
61 
62 	if(random() < 0.10)
63 	{
64 		if(r < 0.33)
65 		{
66 			gi.sound (self, CHAN_VOICE, sound_taunt1, 1, ATTN_NORM, 0);
67 		}
68 		else if(r < 0.66)
69 		{
70 			gi.sound (self, CHAN_VOICE, sound_taunt2, 1, ATTN_NORM, 0);
71 		}
72 		else
73 		{
74 			gi.sound (self, CHAN_VOICE, sound_taunt3, 1, ATTN_NORM, 0);
75 		}
76 	}
77 }
78 
79 //
80 // STAND
81 //
82 
83 
84 mframe_t zboss_frames_stand1 [] =
85 {
86 	ai_stand, 0, NULL,
87 	ai_stand, 0, NULL,
88 	ai_stand, 0, NULL,
89 	ai_stand, 0, NULL,
90 	ai_stand, 0, NULL,
91 	ai_stand, 0, NULL,
92 	ai_stand, 0, NULL,
93 	ai_stand, 0, NULL,
94 	ai_stand, 0, NULL,
95 	ai_stand, 0, NULL,  // 9
96 
97 	ai_stand, 0, NULL,
98 	ai_stand, 0, NULL,
99 	ai_stand, 0, NULL,
100 	ai_stand, 0, NULL,
101 	ai_stand, 0, NULL,
102 	ai_stand, 0, NULL,
103 	ai_stand, 0, NULL,
104 	ai_stand, 0, NULL,
105 	ai_stand, 0, NULL,
106 	ai_stand, 0, NULL,  // 19
107 
108 	ai_stand, 0, NULL,
109 	ai_stand, 0, NULL,
110 	ai_stand, 0, NULL,
111 	ai_stand, 0, NULL,
112 	ai_stand, 0, NULL,
113 	ai_stand, 0, NULL,
114 	ai_stand, 0, NULL,
115 	ai_stand, 0, NULL,
116 	ai_stand, 0, NULL,
117 	ai_stand, 0, NULL,  // 29
118 
119 	ai_stand, 0, NULL,
120 	ai_stand, 0, NULL,
121 };
122 mmove_t zboss_stand1 = {FRAME_stand1start, FRAME_stand1end, zboss_frames_stand1, zboss_stand};
123 
124 
125 
126 
127 mframe_t zboss_frames_stand2 [] =
128 {
129 	ai_stand, 0, NULL, // 32
130 	ai_stand, 0, NULL,
131 	ai_stand, 0, NULL,
132 	ai_stand, 0, NULL,
133 	ai_stand, 0, NULL,
134 	ai_stand, 0, NULL,
135 	ai_stand, 0, NULL,
136 	ai_stand, 0, NULL,
137 	ai_stand, 0, NULL,
138 	ai_stand, 0, NULL, // 41
139 
140 	ai_stand, 0, NULL,
141 	ai_stand, 0, NULL,
142 	ai_stand, 0, NULL,
143 	ai_stand, 0, NULL,
144 	ai_stand, 0, NULL,
145 	ai_stand, 0, NULL,
146 	ai_stand, 0, NULL,
147 	ai_stand, 0, NULL,
148 	ai_stand, 0, NULL,
149 	ai_stand, 0, NULL, // 51
150 
151 	ai_stand, 0, NULL,
152 	ai_stand, 0, NULL,
153 	ai_stand, 0, NULL,
154 	ai_stand, 0, NULL,
155 	ai_stand, 0, NULL	 // 56
156 };
157 mmove_t zboss_stand2 = {FRAME_stand2start, FRAME_stand2end, zboss_frames_stand2, zboss_stand};
158 
159 
zboss_standidle(edict_t * self)160 void zboss_standidle (edict_t *self)
161 {
162 	if (random() < 0.8)
163   {
164 		gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_NORM, 0);
165   	self->monsterinfo.currentmove = &zboss_stand1;
166   }
167   else
168   {
169 		gi.sound (self, CHAN_VOICE, sound_idle2, 1, ATTN_NORM, 0);
170   	self->monsterinfo.currentmove = &zboss_stand2;
171   }
172 }
173 
174 
175 //
176 // Post WALK/RUN leading into ilde.
177 //
178 
179 mframe_t zboss_frames_postwalk [] =
180 {
181 	ai_walk,  3, NULL, // 177
182 	ai_walk,  3, NULL,
183 	ai_walk,  3, NULL,
184 	ai_walk,  3, NULL,
185 	ai_walk,  3, NULL,
186 	ai_walk,  3, NULL,
187 	ai_walk,  3, NULL,
188 	ai_walk,  3, NULL, // 184
189 };
190 mmove_t zboss_move_postwalk = {FRAME_postWalkStart, FRAME_postWalkEnd, zboss_frames_postwalk, zboss_standidle};
191 
192 
zboss_postWalkRun(edict_t * self)193 void zboss_postWalkRun (edict_t *self)
194 {
195 	self->monsterinfo.currentmove = &zboss_move_postwalk;
196 }
197 
198 
199 
200 //
201 // WALK
202 //
203 
204 mframe_t zboss_frames_prewalk [] =
205 {
206 	ai_walk,  3, NULL, //154
207 	ai_walk,  3, NULL,
208 	ai_walk,  3, NULL,
209 	ai_walk,  3, NULL,
210 	ai_walk,  3, NULL,
211 	ai_walk,  3, NULL,
212 	ai_walk,  3, NULL, // 160
213 };
214 mmove_t zboss_move_prewalk = {FRAME_preWalkStart, FRAME_preWalkEnd, zboss_frames_prewalk, zboss_walk2};
215 
216 
217 
218 mframe_t zboss_frames_walk [] =
219 {
220 	ai_walk,  2, NULL,	//161
221 	ai_walk,  3, NULL,
222 	ai_walk,  3, NULL,
223 	ai_walk,  4, NULL,
224 	ai_walk,  4, NULL,
225 	ai_walk,  4, NULL,
226 	ai_walk,  4, NULL,
227 	ai_walk,  3, zboss_walksound,
228 	ai_walk,  4, NULL,
229 	ai_walk,  4, NULL,	// 170
230 	ai_walk,  4, NULL,
231 	ai_walk,  4, NULL,
232 	ai_walk,  3, NULL,
233 	ai_walk,  2, NULL,
234 	ai_walk,  2, NULL,
235 	ai_walk,  3, zboss_walksound,						// 176
236 };
237 mmove_t zboss_move_walk = {FRAME_walkStart, FRAME_walkEnd, zboss_frames_walk, zboss_walk2};
238 
239 
240 
zboss_walk(edict_t * self)241 void zboss_walk (edict_t *self)
242 {
243 	self->monsterinfo.currentmove = &zboss_move_prewalk;
244 }
245 
zboss_walk2(edict_t * self)246 void zboss_walk2(edict_t *self)
247 {
248 	self->monsterinfo.currentmove = &zboss_move_walk;
249 }
250 
251 
252 
253 //
254 // RUN
255 //
256 
257 
258 mframe_t zboss_frames_prerun [] =
259 {
260 	ai_run,  3, NULL, //154
261 	ai_run,  3, NULL,
262 	ai_run,  3, NULL,
263 	ai_run,  3, NULL,
264 	ai_run,  3, NULL,
265 	ai_run,  3, NULL,
266 	ai_run,  3, NULL, // 160
267 };
268 mmove_t zboss_move_prerun = {FRAME_preWalkStart, FRAME_preWalkEnd, zboss_frames_prerun, zboss_run2};
269 
270 
271 mframe_t zboss_frames_run [] =
272 {
273 	ai_run,  2, NULL,	//161
274 	ai_run,  3, NULL,
275 	ai_run,  3, NULL,
276 	ai_run,  4, NULL,
277 	ai_run,  4, NULL,
278 	ai_run,  4, NULL,
279 	ai_run,  4, NULL,
280 	ai_run,  3, zboss_walksound,
281 	ai_run,  4, NULL,
282 	ai_run,  4, NULL,	// 170
283 	ai_run,  4, NULL,
284 	ai_run,  4, NULL,
285 	ai_run,  3, NULL,
286 	ai_run,  2, NULL,
287 	ai_run,  2, NULL,
288 	ai_run,  3, zboss_walksound,						// 176
289 };
290 mmove_t zboss_move_run = {FRAME_walkStart, FRAME_walkEnd, zboss_frames_run, NULL};
291 
292 
zboss_run(edict_t * self)293 void zboss_run (edict_t *self)
294 {
295 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
296     zboss_stand(self);
297 	else
298 		self->monsterinfo.currentmove = &zboss_move_prerun;
299 }
300 
301 
zboss_run2(edict_t * self)302 void zboss_run2 (edict_t *self)
303 {
304 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
305     zboss_stand(self);
306 	else
307 		self->monsterinfo.currentmove = &zboss_move_run;
308 }
309 
310 
311 //
312 // main stand function
313 //
zboss_stand(edict_t * self)314 void zboss_stand (edict_t *self)
315 {
316 	if(self->monsterinfo.currentmove == &zboss_move_prewalk ||
317 				self->monsterinfo.currentmove == &zboss_move_walk ||
318 				self->monsterinfo.currentmove == &zboss_move_prerun ||
319 				self->monsterinfo.currentmove == &zboss_move_run)
320 	{
321 		zboss_postWalkRun(self);
322 	}
323 	else
324 	{
325 		zboss_standidle(self);
326 	}
327 }
328 
329 
330 
331 
332 
333 //
334 // PAIN
335 //
336 
337 
338 mframe_t zboss_frames_pain1 [] =
339 {
340 	ai_move, 0,	NULL,	 // 185
341 	ai_move, 0, NULL,
342 	ai_move, 0, NULL	 // 187
343 };
344 mmove_t zboss_move_pain1 = {FRAME_pain1Start, FRAME_pain1End, zboss_frames_pain1, zboss_run};
345 
346 
347 
348 mframe_t zboss_frames_pain2 [] =
349 {
350 	ai_move, 0,	NULL,	 // 188
351 	ai_move, 0,	NULL,
352 	ai_move, 0,	NULL,
353 	ai_move, 0,	NULL,
354 	ai_move, 0,	NULL	 // 192
355 };
356 mmove_t zboss_move_pain2 = {FRAME_pain2Start, FRAME_pain2End, zboss_frames_pain2, zboss_run};
357 
358 
359 
360 mframe_t zboss_frames_pain3 [] =
361 {
362 	ai_move, 0,	NULL,	// 193
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,	// 202
372 
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,	// 212
383 
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 // 217
389 };
390 mmove_t zboss_move_pain3 = {FRAME_pain3Start, FRAME_pain3End, zboss_frames_pain3, zboss_run};
391 
392 
393 
394 
zboss_pain(edict_t * self,edict_t * other,float kick,int damage)395 void zboss_pain (edict_t *self, edict_t *other, float kick, int damage)
396 {
397 	float r;
398 	float hbreak = (self->max_health / 3.0);
399 
400 	// set the skin
401 	if (self->health < hbreak)
402 	{
403 		self->s.skinnum = 2;
404 	}
405 	else if (self->health < hbreak * 2)
406 	{
407 		self->s.skinnum = 1;
408 	}
409 	else
410 	{
411 		self->s.skinnum = 0;
412 	}
413 
414 	r = random();
415 	if(r < 0.125)
416 	{
417 		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
418 	}
419 	else if(r < 0.25)
420 	{
421 		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
422 	}
423 	else if(r < 0.375)
424 	{
425 		gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
426 	}
427 	else if(r < 0.5)
428 	{
429 		gi.sound (self, CHAN_VOICE, sound_taunt1, 1, ATTN_NORM, 0);
430 	}
431 	else if(r < 0.625)
432 	{
433 		gi.sound (self, CHAN_VOICE, sound_taunt2, 1, ATTN_NORM, 0);
434 	}
435 	else if(r < 0.75)
436 	{
437 		gi.sound (self, CHAN_VOICE, sound_taunt3, 1, ATTN_NORM, 0);
438 	}
439 
440 	if(self->bossFireCount && self->bossFireTimeout < level.time)
441 	{
442 		self->bossFireCount = 0;
443 	}
444 
445 	if(self->bossFireCount > 40 && self->bossFireTimeout > level.time)
446 	{
447 		// that's it, we are pissed...
448 		if(self->zDistance < level.time)
449 		{
450 			fire_empnuke(self, self->s.origin, 1024);
451 			self->zDistance = level.time + 30 + (random() * 5);
452 		}
453 
454 		zboss_attack(self);
455 		self->bossFireCount = 0;
456 		self->bossFireTimeout = 0;
457 		return;
458 	}
459 
460 	self->bossFireCount++;
461 	self->bossFireTimeout = level.time + 1;
462 
463 
464 	if(self->health < (self->max_health / 4) && self->zDistance < level.time)
465 	{
466 		fire_empnuke(self, self->s.origin, 1024);
467 		self->zDistance = level.time + 30 + (random() * 5);
468 	}
469 
470 	if (level.time < self->pain_debounce_time)
471 		return;
472 
473 	self->pain_debounce_time = level.time + 5;
474 
475 	if (skill->value == 3)
476 		return;		// no pain anims in nightmare
477 
478 	if(self->laser)
479 		return;		// while hook is out.
480 
481 	r = random();
482 
483 	if(damage > 150 && r < 0.33)
484 	{
485 	  self->monsterinfo.currentmove = &zboss_move_pain3;
486 	}
487 	else if(damage > 80 && r < 0.66)
488 	{
489 	  self->monsterinfo.currentmove = &zboss_move_pain2;
490 	}
491 	else if(r < 0.60)
492 	{
493 	  self->monsterinfo.currentmove = &zboss_move_pain1;
494 	}
495 }
496 
497 //
498 // MELEE
499 //
500 
501 
zboss_swing(edict_t * self)502 void zboss_swing (edict_t *self)
503 {
504 	static	vec3_t	aim = {MELEE_DISTANCE, 0, -24};
505 	fire_hit (self, aim, (15 + (rand() % 6)), 800);
506 }
507 
508 
509 mframe_t zboss_frames_attack2c [] =
510 {
511 	ai_charge, 0,	NULL,						// 110
512 	ai_charge, 0,	zboss_swing,
513 	ai_charge, 0,	NULL,
514 	ai_charge, 0,	NULL,
515 	ai_charge, 0,	possibleBossTaunt,
516 	ai_charge, 0,	NULL,
517 	ai_charge, 0,	NULL,
518 	ai_charge, 0,	zboss_swing,
519 	ai_charge, 0,	NULL						// 118
520 };
521 mmove_t zboss_move_attack2c = {FRAME_attack2cStart, FRAME_attack2cEnd, zboss_frames_attack2c, zboss_posthook};
522 
523 
524 
525 
zboss_melee2(edict_t * self)526 void zboss_melee2 (edict_t *self)
527 {
528 	self->monsterinfo.currentmove = &zboss_move_attack2c;
529 	gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
530 }
531 
532 
533 mframe_t zboss_frames_premelee [] =
534 {
535 	ai_charge, 0,	NULL,	// 57
536 	ai_charge, 0,	NULL,
537 	ai_charge, 0,	NULL,
538 	ai_charge, 0,	NULL,
539 	ai_charge, 0,	NULL,
540 	ai_charge, 0,	possibleBossTaunt,
541 	ai_charge, 0,	NULL,
542 	ai_charge, 0,	NULL,
543 	ai_charge, 0,	NULL,
544 	ai_charge, 0,	NULL,	// 66
545 };
546 mmove_t zboss_move_premelee = {FRAME_preHookStart, FRAME_preHookEnd, zboss_frames_premelee, zboss_melee2 };
547 
548 // todo, pickup player, and throw...
549 
550 
zboss_melee(edict_t * self)551 void zboss_melee (edict_t *self)
552 {
553 	gi.sound (self, CHAN_BODY, sound_raisegun, 1, ATTN_NORM, 0);
554 	self->monsterinfo.currentmove = &zboss_move_premelee;
555 }
556 
557 
558 
559 //
560 // ATTACK
561 //
562 
563 
564 
565 
566 // Rocket / Hook
567 
568 
569 
570 // Rocket attack
571 
572 mframe_t zboss_frames_attack1b [] =
573 {
574 	ai_charge, 0,	NULL,	// 92
575 	ai_charge, 0,	NULL,
576 	ai_charge, 0,	NULL,
577 	ai_charge, 0,	NULL,
578 	ai_charge, 0,	NULL,
579 	ai_charge, 0,	NULL,
580 	ai_charge, 0,	NULL	// 98
581 };
582 mmove_t zboss_move_attack1b = {FRAME_attack1bStart, FRAME_attack1bEnd, zboss_frames_attack1b, zboss_chooseNextAttack };
583 
584 
zboss_reloadRockets(edict_t * self)585 void zboss_reloadRockets(edict_t *self)
586 {
587 	self->monsterinfo.aiflags &= ~AI_ONESHOTTARGET;
588 	self->monsterinfo.currentmove = &zboss_move_attack1b;
589 }
590 
591 
592 static vec3_t	rocketoffset[]	=
593 {
594 	{-5, -50, 33},
595 	{-5, -39, 27},
596 	{-5, -39, 39},
597 	{-5, -44, 27},
598 	{-5, -44, 39},
599 	{-5, -48, 29},
600 	{-5, -48, 29},
601 };
602 
603 
604 
FireFlare(edict_t * self)605 void FireFlare(edict_t *self)
606 {
607 	vec3_t	forward, right;
608 	vec3_t	start;
609 	vec3_t	dir;
610 	vec3_t	vec;
611 
612 	int offset = (self->s.frame - 71) / 3;
613 
614 	AngleVectors (self->s.angles, forward, right, NULL);
615 
616 	G_ProjectSource (self->s.origin, rocketoffset[offset], forward, right, start);
617 
618 	if(self->monsterinfo.aiflags & AI_ONESHOTTARGET)
619 	{
620 		VectorCopy(	self->monsterinfo.shottarget, vec );
621 	}
622 	else
623 	{
624 		VectorCopy (self->enemy->s.origin, vec);
625 		vec[2] += self->enemy->viewheight;
626 	}
627 
628 	VectorSubtract (vec, start, dir);
629 	VectorNormalize (dir);
630 
631 	if(!(self->monsterinfo.aiflags & AI_ONESHOTTARGET))
632 	{
633 		ANIM_AIM(self, dir);
634 	}
635 	fire_flare (self, start, dir, 10, 1000, 10, 10);
636 
637 	// play shooting sound
638 	gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/flare/shoot.wav"), 1, ATTN_NORM, 0);
639 }
640 
641 
642 
FireRocket(edict_t * self)643 void FireRocket(edict_t *self)
644 {
645 	vec3_t	forward, right;
646 	vec3_t	start;
647 	vec3_t	dir;
648 	vec3_t	vec;
649 
650 	int offset = (self->s.frame - 71) / 3;
651 
652 	AngleVectors (self->s.angles, forward, right, NULL);
653 
654 	G_ProjectSource (self->s.origin, rocketoffset[offset], forward, right, start);
655 
656 	if(self->monsterinfo.aiflags & AI_ONESHOTTARGET)
657 	{
658 		VectorCopy(	self->monsterinfo.shottarget, vec );
659 	}
660 	else
661 	{
662 		VectorCopy (self->enemy->s.origin, vec);
663 		vec[2] += self->enemy->viewheight;
664 	}
665 
666 	vec[0] += (100 - (200 * random()));
667 	vec[1] += (100 - (200 * random()));
668 	vec[2] += (40 - (80 * random()));
669 	VectorSubtract (vec, start, dir);
670 	VectorNormalize (dir);
671 
672 
673 //  ANIM_AIM(self, dir);
674 	fire_rocket (self, start, dir, 70, 500, 70+20, 70);
675 
676 	gi.WriteByte (svc_muzzleflash2);
677 	gi.WriteShort (self - g_edicts);
678 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
679 	gi.multicast (start, MULTICAST_PVS);
680 }
681 
682 
683 
684 
685 
686 mframe_t zboss_frames_attack1a [] =
687 {
688 	ai_charge, 0,	FireFlare,	 // 71
689 	ai_charge, 0,	NULL,
690 	ai_charge, 0,	NULL,
691 	ai_charge, 0,	FireRocket,
692 	ai_charge, 0,	NULL,
693 	ai_charge, 0,	NULL,
694 	ai_charge, 0,	FireRocket,
695 	ai_charge, 0,	NULL,
696 	ai_charge, 0,	NULL,
697 	ai_charge, 0,	FireRocket,
698 	ai_charge, 0,	possibleBossTaunt,
699 	ai_charge, 0,	NULL,
700 	ai_charge, 0,	FireFlare,
701 	ai_charge, 0,	NULL,
702 	ai_charge, 0,	NULL,
703 	ai_charge, 0,	FireRocket,
704 	ai_charge, 0,	NULL,
705 	ai_charge, 0,	NULL,
706 	ai_charge, 0,	FireRocket,
707 	ai_charge, 0,	NULL,
708 	ai_charge, 0,	NULL,				 // 91
709 };
710 mmove_t zboss_move_attack1a = {FRAME_attack1aStart, FRAME_attack1aEnd, zboss_frames_attack1a, zboss_reloadRockets };
711 
712 
713 
714 
715 
716 
717 // hook
718 
719 
zboss_reelInGraaple2(edict_t * self)720 void zboss_reelInGraaple2(edict_t *self)
721 {
722 	vec3_t	vec, dir;
723 	float length;
724 	edict_t *enemy = self->laser->enemy;
725 	vec3_t	hookoffset	= {-5, -24, 34};
726 	vec3_t	forward, right;
727 
728 	AngleVectors (self->s.angles, forward, right, NULL);
729 	G_ProjectSource(self->s.origin, hookoffset, forward, right, vec);
730 	VectorSubtract (vec, self->laser->s.origin, dir);
731 	length = VectorLength (dir);
732 
733 	if(length <= 80 || (self->laser->think == HookDragThink && self->laser->powerarmor_time < level.time))
734 	{
735 		G_FreeEdict(self->laser);
736 		self->laser = NULL;
737 
738 		self->s.modelindex3 = gi.modelindex ("models/monsters/bossz/grapple/tris.md2");
739 
740 		if(enemy)
741 		{
742 			VectorClear(enemy->velocity);
743 			zboss_melee2(self);
744 		}
745 		else
746 		{
747 			zboss_chooseNextAttack(self);
748 		}
749 	}
750 	else
751 	{
752 		zboss_reelInGraaple(self);
753 	}
754 }
755 
756 
757 mframe_t zboss_frames_attack2b [] =
758 {
759 	ai_charge, 0,	NULL,		 // 107
760 	ai_charge, 0,	NULL,
761 	ai_charge, 0,	NULL		 // 109
762 };
763 mmove_t zboss_move_attack2b = {FRAME_attack2bStart, FRAME_attack2bEnd, zboss_frames_attack2b, zboss_reelInGraaple2 };
764 
765 
HookDragThink(edict_t * self)766 void HookDragThink (edict_t *self)
767 {
768 	vec3_t	dir, vec;
769 	float length, speed;
770 	vec3_t	hookoffset	= {-5, -24, 34};
771 	vec3_t	forward, right;
772 	vec3_t  offset = {0, 0, 0};
773 
774 	if(self->enemy && self->enemy->health > 0)
775 	{
776 		VectorCopy (self->enemy->s.origin, self->s.origin);
777 	}
778 
779 	VectorSubtract (self->owner->s.origin, self->s.origin, dir);
780 	length = VectorLength (dir);
781 
782 	AngleVectors (self->owner->s.angles, forward, right, NULL);
783 	G_ProjectSource(self->owner->s.origin, hookoffset, forward, right, vec);
784 
785 	VectorSubtract (vec, self->s.origin, dir);
786 	speed = VectorLength (dir);
787 	VectorNormalize (dir);
788 /*
789 	if(speed > 1000)
790 	{
791 		speed = 1000;
792 	}
793 	else if(speed < 500)
794 	{
795 		speed = (speed * 2) + 100;
796 	}
797 */
798 	speed = 1000;
799 	VectorScale (dir, speed, self->velocity);
800 
801 	if(self->enemy && self->enemy->health > 0)
802 	{
803 		VectorCopy (self->velocity, self->enemy->velocity);
804 		self->enemy->velocity[2] *= 1.3;
805 	}
806 
807 	gi.WriteByte (svc_temp_entity);
808 #if 0 //def USE_GRAPPLE_CABLE
809 	gi.WriteByte (TE_GRAPPLE_CABLE);
810 	gi.WriteShort (self - g_edicts);
811 	gi.WritePosition (self->s.origin);
812 	gi.WritePosition (vec);
813 	gi.WritePosition (offset);
814 #else
815 	gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
816 	gi.WriteShort (self - g_edicts);
817 	gi.WritePosition (self->s.origin);
818 	gi.WritePosition (vec);
819 #endif
820 	gi.multicast (self->s.origin, MULTICAST_PVS);
821 
822 	self->nextthink = level.time + FRAMETIME;
823 }
824 
825 
HookTouch(edict_t * ent,edict_t * other,cplane_t * plane,csurface_t * surf)826 void HookTouch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
827 {
828 	if (other == ent->owner)
829 		return;
830 
831 	if (other->takedamage)
832 	{
833 		gi.sound (ent, CHAN_WEAPON, sound_hookimpact, 1, ATTN_NORM, 0);
834 		T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, 10, 0, 0, MOD_ROCKET);
835 	}
836 
837 	if(other->client && other->health > 0)
838 	{ // alive... Let's drag the bastard back...
839 		ent->enemy = other;
840 	}
841 
842 	ent->powerarmor_time = level.time + 15;
843 	VectorClear(ent->velocity);
844 	ent->nextthink = level.time + FRAMETIME;
845 	ent->think = HookDragThink;
846 	ent->s.frame = 283;
847 }
848 
849 
HookThink(edict_t * self)850 void HookThink(edict_t *self)
851 {
852 	vec3_t	vec;
853 	vec3_t	hookoffset	= {-3, -24, 34};
854 	vec3_t	forward, right;
855 	vec3_t  offset = {0, 0, 0};
856 
857 	if(self->powerarmor_time < level.time)
858 	{
859 		self->powerarmor_time = level.time + 15;
860 		VectorClear(self->velocity);
861 		self->enemy = NULL;
862 		self->think = HookDragThink;
863 		self->s.frame = 283;
864 	}
865 
866 
867 	AngleVectors (self->owner->s.angles, forward, right, NULL);
868 	G_ProjectSource(self->owner->s.origin, hookoffset, forward, right, vec);
869 
870 	gi.WriteByte (svc_temp_entity);
871 #if 0 //def USE_GRAPPLE_CABLE
872 	gi.WriteByte (TE_GRAPPLE_CABLE);
873 	gi.WriteShort (self - g_edicts);
874 	gi.WritePosition (self->s.origin);
875 	gi.WritePosition (vec);
876 	gi.WritePosition (offset);
877 #else
878 	gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
879 	gi.WriteShort (self - g_edicts);
880 	gi.WritePosition (self->s.origin);
881 	gi.WritePosition (vec);
882 #endif
883 	gi.multicast (self->s.origin, MULTICAST_PVS);
884 
885 	self->nextthink = level.time + FRAMETIME;
886 }
887 
888 
FireHook(edict_t * self)889 void FireHook(edict_t *self)
890 {
891 	vec3_t	forward, right;
892 	vec3_t	start;
893 	vec3_t	dir;
894 	vec3_t	vec;
895 	vec3_t	hookoffset	= {-1, -24, 34};
896 	edict_t	*hook;
897 	float speed;
898 
899 	AngleVectors (self->s.angles, forward, right, NULL);
900 
901 	G_ProjectSource (self->s.origin, hookoffset, forward, right, start);
902 	VectorCopy (self->enemy->s.origin, vec);
903 	vec[2] += self->enemy->viewheight;
904 	VectorSubtract (vec, start, dir);
905 	VectorNormalize (dir);
906 
907   ANIM_AIM(self, dir);
908 
909 	self->s.modelindex3 = 0;
910 
911 	speed = 1000;
912 
913 	gi.sound (self, CHAN_WEAPON, sound_hooklaunch, 1, ATTN_NORM, 0);
914 
915 	self->laser = hook = G_Spawn();
916 	VectorCopy (start, hook->s.origin);
917 	VectorCopy (dir, hook->movedir);
918 	vectoangles (dir, hook->s.angles);
919 	VectorScale (dir, speed, hook->velocity);
920 	hook->movetype = MOVETYPE_FLYMISSILE;
921 	hook->clipmask = MASK_SHOT;
922 	hook->solid = SOLID_BBOX;
923 	VectorClear (hook->mins);
924 	VectorClear (hook->maxs);
925 	hook->s.modelindex = gi.modelindex ("models/monsters/bossz/grapple/tris.md2");
926 	hook->s.frame = 282;
927 	hook->owner = self;
928 	hook->touch = HookTouch;
929 	hook->powerarmor_time = level.time + 8000 / speed;
930 	hook->nextthink = level.time + FRAMETIME;
931 	hook->think = HookThink;
932 	hook->s.sound = sound_hookfly; // replace...
933 	hook->classname = "bosshook";
934 
935 	gi.linkentity (hook);
936 }
937 
938 
zboss_reelInGraaple(edict_t * self)939 void zboss_reelInGraaple(edict_t *self)
940 {
941 	self->monsterinfo.currentmove = &zboss_move_attack2b;
942 }
943 
944 
945 mframe_t zboss_frames_attack2a [] =
946 {
947 	ai_charge, 0,	NULL,			 // 99
948 	ai_charge, 0,	NULL,
949 	ai_charge, 0,	NULL,
950 	ai_charge, 0,	possibleBossTaunt,
951 	ai_charge, 0,	NULL,
952 	ai_charge, 0,	FireHook,	 // 104
953 	ai_charge, 0,	NULL,
954 	ai_charge, 0,	NULL,			 // 106
955 };
956 mmove_t zboss_move_attack2a = {FRAME_attack2aStart, FRAME_attack2aEnd, zboss_frames_attack2a, zboss_reelInGraaple };
957 
958 
959 
960 
961 
962 mframe_t zboss_frames_posthook [] =
963 {
964 	ai_charge, 0,	NULL,	 // 136
965 	ai_charge, 0,	NULL,
966 	ai_charge, 0,	NULL,
967 	ai_charge, 0,	NULL,
968 	ai_charge, 0,	NULL,
969 	ai_charge, 0,	NULL,	 // 141
970 };
971 mmove_t zboss_move_posthook = {FRAME_postHookStart, FRAME_postHookEnd, zboss_frames_posthook, zboss_run };
972 
973 
zboss_posthook(edict_t * self)974 void zboss_posthook(edict_t *self)
975 {
976 	self->monsterinfo.currentmove = &zboss_move_posthook;
977 }
978 
979 
980 
981 
zboss_chooseHookRocket(edict_t * self)982 void zboss_chooseHookRocket(edict_t *self)
983 {
984 	if(random() < 0.2 && !(self->monsterinfo.aiflags & AI_ONESHOTTARGET))
985 	{
986 		self->monsterinfo.currentmove = &zboss_move_attack2a;
987 	}
988 	else
989 	{
990 		self->monsterinfo.currentmove = &zboss_move_attack1a;
991 	}
992 }
993 
994 
995 mframe_t zboss_frames_prehook [] =
996 {
997 	ai_charge, 0,	NULL,	// 57
998 	ai_charge, 0,	NULL,
999 	ai_charge, 0,	NULL,
1000 	ai_charge, 0,	NULL,
1001 	ai_charge, 0,	NULL,
1002 	ai_charge, 0,	NULL,
1003 	ai_charge, 0,	NULL,
1004 	ai_charge, 0,	NULL,
1005 	ai_charge, 0,	NULL,
1006 	ai_charge, 0,	NULL,	// 66
1007 };
1008 mmove_t zboss_move_prehook = {FRAME_preHookStart, FRAME_preHookEnd, zboss_frames_prehook, zboss_chooseHookRocket };
1009 
1010 
1011 
1012 
1013 
1014 // Plasma Cannon
1015 
1016 
PlasmaballBlastAnim(edict_t * ent)1017 void PlasmaballBlastAnim(edict_t	*ent)
1018 {
1019   ent->s.frame++;
1020   ent->s.skinnum++;
1021 
1022   if(ent->s.frame > 1)
1023   {
1024 		G_FreeEdict(ent);
1025 		return;
1026   }
1027   else
1028   {
1029     ent->nextthink = level.time + FRAMETIME;
1030   }
1031 }
1032 
1033 
Plasmaball_Explode(edict_t * ent)1034 void Plasmaball_Explode (edict_t *ent)
1035 {
1036 	//FIXME: if we are onground then raise our Z just a bit since we are a point?
1037 	if (ent->enemy)
1038 	{
1039 		float	points;
1040 		vec3_t	v;
1041 		vec3_t	dir;
1042 
1043 		VectorAdd (ent->enemy->mins, ent->enemy->maxs, v);
1044 		VectorMA (ent->enemy->s.origin, 0.5, v, v);
1045 		VectorSubtract (ent->s.origin, v, v);
1046 		points = ent->dmg - 0.5 * VectorLength (v);
1047 		VectorSubtract (ent->enemy->s.origin, ent->s.origin, dir);
1048 		T_Damage (ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, MOD_UNKNOWN);
1049 	}
1050 
1051 	T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, MOD_UNKNOWN);
1052 
1053 	VectorMA (ent->s.origin, -0.02, ent->velocity, ent->s.origin);
1054 	VectorClear(ent->velocity);
1055 
1056 	ent->movetype = MOVETYPE_NONE;
1057 	ent->s.modelindex = gi.modelindex("models/objects/b_explode/tris.md2");
1058 	ent->s.effects &= ~EF_BFG & ~EF_ANIM_ALLFAST;
1059 	ent->s.frame = 0;
1060 	ent->s.skinnum = 6;
1061 //  ent->s.renderfx = RF_TRANSLUCENT | RF_FULLBRIGHT;
1062 //  ent->s.renderfx = RF_TRANSLUCENT;
1063 
1064 	gi.sound (ent, CHAN_AUTO, sound_plamsaballexplode, 1, ATTN_NORM, 0);
1065 
1066 	ent->think = PlasmaballBlastAnim;
1067 	ent->nextthink = level.time + FRAMETIME;
1068 }
1069 
1070 
Plasmaball_Touch(edict_t * ent,edict_t * other,cplane_t * plane,csurface_t * surf)1071 static void Plasmaball_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
1072 {
1073 	if (other == ent->owner)
1074 		return;
1075 
1076 	if (surf && (surf->flags & SURF_SKY))
1077 	{
1078 		G_FreeEdict (ent);
1079 		return;
1080 	}
1081 
1082 	ent->enemy = other;
1083 	Plasmaball_Explode (ent);
1084 }
1085 
1086 
fire_plasmaCannon(edict_t * self,vec3_t start,vec3_t aimdir,int damage,int speed,float timer,float damage_radius,float distance)1087 void fire_plasmaCannon (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, float distance)
1088 {
1089 	edict_t	*plasmaball;
1090 	vec3_t	dir;
1091 	vec3_t	forward, right, up;
1092 
1093 	vectoangles (aimdir, dir);
1094 	AngleVectors (dir, forward, right, up);
1095 
1096 	plasmaball = G_Spawn();
1097 	VectorCopy (start, plasmaball->s.origin);
1098 	VectorScale (aimdir, speed, plasmaball->velocity);
1099 	VectorMA (plasmaball->velocity, (distance - 500) + crandom() * 10.0, up, plasmaball->velocity);
1100 	VectorMA (plasmaball->velocity, crandom() * 10.0, right, plasmaball->velocity);
1101 	VectorSet (plasmaball->avelocity, 300, 300, 300);
1102 	plasmaball->movetype = MOVETYPE_BOUNCE;
1103 	plasmaball->clipmask = MASK_SHOT;
1104 	plasmaball->solid = SOLID_BBOX;
1105 	VectorClear (plasmaball->mins);
1106 	VectorClear (plasmaball->maxs);
1107 	plasmaball->s.modelindex = gi.modelindex ("sprites/plasma1.sp2");
1108 	plasmaball->s.effects = EF_BFG | EF_ANIM_ALLFAST;
1109 	plasmaball->owner = self;
1110 	plasmaball->touch = Plasmaball_Touch;
1111 	plasmaball->nextthink = level.time + timer;
1112 	plasmaball->think = Plasmaball_Explode;
1113 	plasmaball->dmg = damage;
1114 	plasmaball->dmg_radius = damage_radius;
1115 	plasmaball->classname = "plasmaball";
1116 	plasmaball->s.sound = sound_plamsaballfly;
1117 
1118 	gi.sound (self, CHAN_AUTO, sound_plamsaballfire, 1, ATTN_NORM, 0);
1119 	gi.linkentity (plasmaball);
1120 }
1121 
1122 
1123 
1124 static vec3_t cannonoffset[]	=
1125 {
1126 	{-19, -44, 30},
1127 	{-14, -33, 32},
1128 	{-4 , -45, 32},
1129 	{-2 , -34, 32},
1130 	{  7, -49, 32},
1131 	{  6, -36, 34},
1132 	{  6, -36, 34},
1133 };
1134 
1135 
FireCannon(edict_t * self)1136 void FireCannon(edict_t *self)
1137 {
1138 	vec3_t	forward, right;
1139 	vec3_t	start;
1140 	vec3_t	dir;
1141 	vec3_t	vec;
1142 	float distance;
1143 
1144 	int offset = (self->s.frame - 119) / 2;
1145 
1146 	AngleVectors (self->s.angles, forward, right, NULL);
1147 
1148 	G_ProjectSource (self->s.origin, cannonoffset[offset], forward, right, start);
1149 
1150 	if(self->monsterinfo.aiflags & AI_ONESHOTTARGET)
1151 	{
1152 		VectorCopy(	self->monsterinfo.shottarget, vec );
1153 	}
1154 	else
1155 	{
1156 		VectorCopy (self->enemy->s.origin, vec);
1157 		vec[2] += self->enemy->viewheight;
1158 	}
1159 
1160 	if(self->timeout)
1161 	{
1162 		if(self->seq)
1163 		{
1164 			VectorNegate(right, right);
1165 		}
1166 		VectorMA (vec, self->timeout, right, vec);
1167 	}
1168 	self->timeout -= 50;
1169 
1170 	VectorSubtract (vec, start, dir);
1171 	VectorNormalize (dir);
1172 
1173 	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
1174 	distance = VectorLength (vec);
1175 
1176 	if(distance < 700)
1177 	{
1178 		distance = 700;
1179 	}
1180 
1181 //  ANIM_AIM(self, dir);
1182 	if(skill->value < 2)
1183 	{
1184 		fire_plasmaCannon (self, start, dir, 90, 700, 2.5, 90+40, distance);
1185 	}
1186 	else if(skill->value < 3)
1187 	{
1188 		fire_plasmaCannon (self, start, dir, 90, (int)(distance * 1.2), 2.5, 90+40, distance);
1189 	}
1190 	else
1191 	{
1192 		fire_plasmaCannon (self, start, dir, 90, (int)(distance * 1.6), 2.5, 90+40, distance);
1193 	}
1194 }
1195 
1196 
1197 
1198 mframe_t zboss_frames_attack3 [] =
1199 {
1200 	ai_charge, 0,	FireCannon,	// 119
1201 	ai_charge, 0,	NULL,
1202 	ai_charge, 0,	FireCannon,	// 121
1203 	ai_charge, 0,	NULL,
1204 	ai_charge, 0,	FireCannon,	// 123
1205 	ai_charge, 0,	NULL,
1206 	ai_charge, 0,	FireCannon,	// 125
1207 	ai_charge, 0,	possibleBossTaunt,
1208 	ai_charge, 0,	FireCannon,	// 127
1209 	ai_charge, 0,	NULL,
1210 	ai_charge, 0,	FireCannon,	// 129
1211 	ai_charge, 0,	NULL,
1212 	ai_charge, 0,	FireCannon,	// 131
1213 	ai_charge, 0,	NULL,				// 132
1214 };
1215 mmove_t zboss_move_attack3 = {FRAME_attack3Start, FRAME_attack3End, zboss_frames_attack3, zboss_chooseNextAttack };
1216 
1217 
zboss_fireCannons(edict_t * self)1218 void zboss_fireCannons(edict_t *self)
1219 {
1220 	self->monsterinfo.currentmove = &zboss_move_attack3;
1221 
1222 //	self->seq = (random() > 0.5);
1223 	self->seq = 0;
1224 	self->timeout = 150;
1225 }
1226 
1227 
1228 mframe_t zboss_frames_precannon [] =
1229 {
1230 	ai_charge, 0,	NULL,	// 67
1231 	ai_charge, 0,	NULL,
1232 	ai_charge, 0,	NULL,
1233 	ai_charge, 0,	NULL,	// 70
1234 };
1235 mmove_t zboss_move_precannon = {FRAME_preCannonStart, FRAME_preCannonEnd, zboss_frames_precannon, zboss_fireCannons };
1236 
1237 
1238 
1239 
1240 mframe_t zboss_frames_postcannon [] =
1241 {
1242 	ai_charge, 0,	NULL,	// 133
1243 	ai_charge, 0,	NULL,
1244 	ai_charge, 0,	NULL,	// 135
1245 };
1246 mmove_t zboss_move_postcannon = {FRAME_postCannonStart, FRAME_postCannonEnd, zboss_frames_postcannon, zboss_run };
1247 
1248 
1249 
zboss_postcannon(edict_t * self)1250 void zboss_postcannon(edict_t *self)
1251 {
1252 	self->monsterinfo.currentmove = &zboss_move_postcannon;
1253 }
1254 
1255 
1256 
1257 
1258 // switching in mid attack...
1259 
1260 
1261 mframe_t zboss_frames_h2c [] =
1262 {
1263 	ai_charge, 0,	NULL,	// 142
1264 	ai_charge, 0,	NULL,
1265 	ai_charge, 0,	NULL,
1266 	ai_charge, 0,	NULL,
1267 	ai_charge, 0,	NULL,
1268 	ai_charge, 0,	NULL,	// 147
1269 };
1270 mmove_t zboss_move_h2c = {FRAME_attackH2CStart, FRAME_attackH2CEnd, zboss_frames_h2c, zboss_fireCannons };
1271 
1272 
1273 mframe_t zboss_frames_c2h [] =
1274 {
1275 	ai_charge, 0,	NULL,	// 148
1276 	ai_charge, 0,	NULL,
1277 	ai_charge, 0,	NULL,
1278 	ai_charge, 0,	possibleBossTaunt,
1279 	ai_charge, 0,	NULL,
1280 	ai_charge, 0,	NULL,	// 153
1281 };
1282 mmove_t zboss_move_c2h = {FRAME_attackC2HStart, FRAME_attackC2HEnd, zboss_frames_c2h, zboss_chooseHookRocket };
1283 
1284 
1285 
1286 
zboss_chooseNextAttack(edict_t * self)1287 void zboss_chooseNextAttack(edict_t *self)
1288 {
1289 	if (self->enemy == NULL)
1290 		return;
1291 
1292 	self->monsterinfo.aiflags &= ~AI_ONESHOTTARGET;
1293 
1294 	if(random() < 0.5 && self->enemy)
1295 	{
1296 		if(random() < 0.4)
1297 		{
1298 			if(self->monsterinfo.currentmove == &zboss_move_attack3)
1299 			{
1300 				gi.sound (self, CHAN_BODY, sound_switchattacks, 1, ATTN_NORM, 0);
1301 				self->monsterinfo.currentmove = &zboss_move_c2h;
1302 			}
1303 			else
1304 			{
1305 				zboss_chooseHookRocket(self);
1306 			}
1307 		}
1308 		else
1309 		{
1310 			if(self->monsterinfo.currentmove == &zboss_move_attack3)
1311 			{
1312 				zboss_fireCannons(self);
1313 			}
1314 			else
1315 			{
1316 				gi.sound (self, CHAN_BODY, sound_switchattacks, 1, ATTN_NORM, 0);
1317 				self->monsterinfo.currentmove = &zboss_move_h2c;
1318 			}
1319 		}
1320 	}
1321 	else
1322 	{
1323 		gi.sound (self, CHAN_BODY, sound_lowergun, 1, ATTN_NORM, 0);
1324 
1325 		if(self->monsterinfo.currentmove == &zboss_move_attack3)
1326 		{
1327 			zboss_postcannon(self);
1328 		}
1329 		else
1330 		{
1331 			zboss_posthook(self);
1332 		}
1333 	}
1334 }
1335 
1336 
1337 
1338 
zboss_attack(edict_t * self)1339 void zboss_attack (edict_t *self)
1340 {
1341 	if (self->enemy == NULL)
1342 		return;
1343 
1344 	gi.sound (self, CHAN_BODY, sound_raisegun, 1, ATTN_NORM, 0);
1345 
1346 	if(random() < 0.4)
1347 	{
1348 		self->monsterinfo.currentmove = &zboss_move_prehook;
1349 	}
1350 	else
1351 	{
1352 		self->monsterinfo.currentmove = &zboss_move_precannon;
1353 	}
1354 }
1355 
1356 
1357 
1358 
1359 
1360 /*
1361 ===
1362 Death Stuff Starts
1363 ===
1364 */
1365 
zboss_dead(edict_t * self)1366 void zboss_dead (edict_t *self)
1367 {
1368 	VectorSet (self->mins, -32, -74, -30);
1369 	VectorSet (self->maxs, 32, 40, 12);
1370 	self->movetype = MOVETYPE_TOSS;
1371 	self->svflags |= SVF_DEADMONSTER;
1372 	self->nextthink = 0;
1373 	gi.linkentity (self);
1374 }
1375 
1376 
1377 mframe_t zboss_frames_death1 [] =
1378 {
1379 	ai_move, 0,	NULL,	// 218
1380 	ai_move, 0,	NULL,
1381 	ai_move, 0,	NULL,
1382 	ai_move, 0,	NULL,
1383 	ai_move, 0,	NULL,
1384 	ai_move, 0,	NULL,
1385 	ai_move, 0,	NULL,
1386 	ai_move, 0,	NULL,
1387 	ai_move, 0,	NULL,
1388 	ai_move, 0,	NULL,	// 227
1389 
1390 	ai_move, 0,	NULL, // 228
1391 	ai_move, 0,	NULL,
1392 	ai_move, 0,	NULL,
1393 	ai_move, 0,	NULL,
1394 	ai_move, 0,	NULL,
1395 	ai_move, 0,	NULL,
1396 	ai_move, 0,	NULL,
1397 	ai_move, 0,	NULL,
1398 	ai_move, 0,	NULL,	// 236
1399 };
1400 mmove_t zboss_move_death1 = {FRAME_die1Start, FRAME_die1End, zboss_frames_death1, zboss_dead};
1401 
1402 
1403 
FireDeadRocket1(edict_t * self)1404 void FireDeadRocket1(edict_t *self)
1405 {
1406 	vec3_t	forward, right;
1407 	vec3_t	start;
1408 	vec3_t	rocketoffset	= {-26, -26, 25};
1409 
1410 	AngleVectors (self->s.angles, forward, right, NULL);
1411 
1412 	G_ProjectSource (self->s.origin, rocketoffset, forward, right, start);
1413 
1414 	fire_rocket (self, start, forward, 70, 500, 70+20, 70);
1415 
1416 	gi.WriteByte (svc_muzzleflash2);
1417 	gi.WriteShort (self - g_edicts);
1418 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
1419 	gi.multicast (start, MULTICAST_PVS);
1420 }
1421 
1422 
FireDeadRocket2(edict_t * self)1423 void FireDeadRocket2(edict_t *self)
1424 {
1425 	vec3_t	forward, right;
1426 	vec3_t	start;
1427 	vec3_t	rocketoffset	= {-16, -21, 20};
1428 
1429 	AngleVectors (self->s.angles, forward, right, NULL);
1430 
1431 	G_ProjectSource (self->s.origin, rocketoffset, forward, right, start);
1432 
1433 	forward[1] += 10;
1434 	fire_rocket (self, start, forward, 70, 500, 70+20, 70);
1435 
1436 	gi.WriteByte (svc_muzzleflash2);
1437 	gi.WriteShort (self - g_edicts);
1438 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
1439 	gi.multicast (start, MULTICAST_PVS);
1440 }
1441 
1442 
FireDeadRocket3(edict_t * self)1443 void FireDeadRocket3(edict_t *self)
1444 {
1445 	vec3_t	forward, right, up;
1446 	vec3_t	start;
1447 	vec3_t	rocketoffset	= {-17, -20, 30};
1448 
1449 	AngleVectors (self->s.angles, forward, right, up);
1450 
1451 	G_ProjectSource (self->s.origin, rocketoffset, forward, right, start);
1452 
1453 	fire_rocket (self, start, up, 70, 500, 70+20, 70);
1454 
1455 	gi.WriteByte (svc_muzzleflash2);
1456 	gi.WriteShort (self - g_edicts);
1457 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
1458 	gi.multicast (start, MULTICAST_PVS);
1459 }
1460 
1461 
1462 
FireDeadRocket4(edict_t * self)1463 void FireDeadRocket4(edict_t *self)
1464 {
1465 	vec3_t	forward, right, up;
1466 	vec3_t	start;
1467 	vec3_t	rocketoffset	= {-8, -16, 17};
1468 
1469 	AngleVectors (self->s.angles, forward, right, up);
1470 
1471 	G_ProjectSource (self->s.origin, rocketoffset, forward, right, start);
1472 
1473 	fire_rocket (self, start, up, 70, 500, 70+20, 70);
1474 
1475 	gi.WriteByte (svc_muzzleflash2);
1476 	gi.WriteShort (self - g_edicts);
1477 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
1478 	gi.multicast (start, MULTICAST_PVS);
1479 }
1480 
1481 
FireDeadRocket5(edict_t * self)1482 void FireDeadRocket5(edict_t *self)
1483 {
1484 	vec3_t	forward, right, up;
1485 	vec3_t	start;
1486 	vec3_t	rocketoffset	= {-10, -16, 30};
1487 
1488 	AngleVectors (self->s.angles, forward, right, up);
1489 
1490 	G_ProjectSource (self->s.origin, rocketoffset, forward, right, start);
1491 	VectorNegate(forward, forward);
1492 
1493 	fire_rocket (self, start, forward, 70, 500, 70+20, 70);
1494 
1495 	gi.WriteByte (svc_muzzleflash2);
1496 	gi.WriteShort (self - g_edicts);
1497 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
1498 	gi.multicast (start, MULTICAST_PVS);
1499 }
1500 
FireDeadRocket6(edict_t * self)1501 void FireDeadRocket6(edict_t *self)
1502 {
1503 	vec3_t	forward, right, up;
1504 	vec3_t	start;
1505 	vec3_t	rocketoffset	= {0, -18, 25};
1506 
1507 	AngleVectors (self->s.angles, forward, right, up);
1508 
1509 	G_ProjectSource (self->s.origin, rocketoffset, forward, right, start);
1510 	VectorNegate(forward, forward);
1511 	forward[1]  -= 10;
1512 
1513 	fire_rocket (self, start, forward, 70, 500, 70+20, 70);
1514 
1515 	gi.WriteByte (svc_muzzleflash2);
1516 	gi.WriteShort (self - g_edicts);
1517 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
1518 	gi.multicast (start, MULTICAST_PVS);
1519 }
1520 
1521 
FireDeadRocket7(edict_t * self)1522 void FireDeadRocket7(edict_t *self)
1523 {
1524 	vec3_t	forward, right, up;
1525 	vec3_t	start;
1526 	vec3_t	rocketoffset	= {17, -27, 30};
1527 
1528 	AngleVectors (self->s.angles, forward, right, up);
1529 
1530 	G_ProjectSource (self->s.origin, rocketoffset, forward, right, start);
1531 	VectorNegate(forward, forward);
1532 	forward[1]  -= 10;
1533 
1534 	fire_rocket (self, start, forward, 70, 500, 70+20, 70);
1535 
1536 	gi.WriteByte (svc_muzzleflash2);
1537 	gi.WriteShort (self - g_edicts);
1538 	gi.WriteByte (MZ2_BOSS2_ROCKET_1);
1539 	gi.multicast (start, MULTICAST_PVS);
1540 }
1541 
FireDeadCannon1(edict_t * self)1542 void FireDeadCannon1(edict_t *self)
1543 {
1544 	vec3_t	forward, right;
1545 	vec3_t	start;
1546 	vec3_t	cannonoffset	= {9, -46, 33};
1547 
1548 	AngleVectors (self->s.angles, forward, right, NULL);
1549 
1550 	G_ProjectSource (self->s.origin, cannonoffset, forward, right, start);
1551 
1552 	fire_plasmaCannon (self, start, forward, 90, 700, 2.5, 90+40, 700);
1553 
1554 	gi.WriteByte (svc_muzzleflash2);
1555 	gi.WriteShort (self - g_edicts);
1556 	gi.WriteByte (MZ2_GUNNER_GRENADE_1);
1557 	gi.multicast (start, MULTICAST_PVS);
1558 }
1559 
1560 
FireDeadCannon2(edict_t * self)1561 void FireDeadCannon2(edict_t *self)
1562 {
1563 	vec3_t	forward, right;
1564 	vec3_t	start;
1565 	vec3_t	cannonoffset	= {3, -31, 37};
1566 
1567 	AngleVectors (self->s.angles, forward, right, NULL);
1568 
1569 	G_ProjectSource (self->s.origin, cannonoffset, forward, right, start);
1570 
1571 	fire_plasmaCannon (self, start, forward, 90, 700, 2.5, 90+40, 700);
1572 
1573 	gi.WriteByte (svc_muzzleflash2);
1574 	gi.WriteShort (self - g_edicts);
1575 	gi.WriteByte (MZ2_GUNNER_GRENADE_1);
1576 	gi.multicast (start, MULTICAST_PVS);
1577 }
1578 
1579 
FireDeadCannon3(edict_t * self)1580 void FireDeadCannon3(edict_t *self)
1581 {
1582 	vec3_t	forward, right;
1583 	vec3_t	start;
1584 	vec3_t	cannonoffset	= {-21, -19, 24};
1585 
1586 	AngleVectors (self->s.angles, forward, right, NULL);
1587 
1588 	G_ProjectSource (self->s.origin, cannonoffset, forward, right, start);
1589 
1590 	fire_plasmaCannon (self, start, forward, 90, 700, 2.5, 90+40, 700);
1591 
1592 	gi.WriteByte (svc_muzzleflash2);
1593 	gi.WriteShort (self - g_edicts);
1594 	gi.WriteByte (MZ2_GUNNER_GRENADE_1);
1595 	gi.multicast (start, MULTICAST_PVS);
1596 }
1597 
1598 
1599 
DeadHookTouch(edict_t * ent,edict_t * other,cplane_t * plane,csurface_t * surf)1600 void DeadHookTouch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
1601 {
1602 	if (other == ent->owner)
1603 		return;
1604 
1605 	if (other->takedamage)
1606 	{
1607 		gi.sound (ent, CHAN_WEAPON, sound_hookimpact, 1, ATTN_NORM, 0);
1608 		T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, 10, 0, 0, MOD_ROCKET);
1609 	}
1610 
1611 	G_FreeEdict(ent);
1612 }
1613 
FireDeadGrapple(edict_t * self)1614 void FireDeadGrapple(edict_t *self)
1615 {
1616 	vec3_t	forward, right, up;
1617 	vec3_t	start;
1618 	vec3_t	hookoffset	= {-35, 8, 28};
1619 	edict_t	*hook;
1620 	float speed;
1621 
1622 	if(self->s.modelindex3 == 0)  // hook already out...
1623 		return;
1624 
1625 	AngleVectors (self->s.angles, forward, right, up);
1626 
1627 	G_ProjectSource (self->s.origin, hookoffset, forward, right, start);
1628 
1629 	self->s.modelindex3 = 0;
1630 
1631 	speed = 500;
1632 
1633 	gi.sound (self, CHAN_WEAPON, sound_hooklaunch, 1, ATTN_NORM, 0);
1634 
1635 	hook = G_Spawn();
1636 	VectorCopy (start, hook->s.origin);
1637 	VectorCopy (up, hook->movedir);
1638 	vectoangles (up, hook->s.angles);
1639 	VectorScale (up, speed, hook->velocity);
1640 	hook->movetype = MOVETYPE_FLYMISSILE;
1641 	hook->clipmask = MASK_SHOT;
1642 	hook->solid = SOLID_BBOX;
1643 	VectorClear (hook->mins);
1644 	VectorClear (hook->maxs);
1645 	hook->s.modelindex = gi.modelindex ("models/monsters/bossz/grapple/tris.md2");
1646 	hook->s.frame = 282;
1647 	hook->owner = self;
1648 	hook->touch = DeadHookTouch;
1649 	hook->nextthink = level.time + 8000 / speed;
1650 	hook->think = G_FreeEdict;
1651 	hook->s.sound = sound_hookfly; // replace...
1652 	hook->classname = "bosshook";
1653 
1654 	gi.linkentity (hook);
1655 }
1656 
1657 
1658 
1659 mframe_t zboss_frames_death2 [] =
1660 {
1661 	ai_move, 0,	NULL,							// 237
1662 	ai_move, 0,	NULL,
1663 	ai_move, 0,	NULL,
1664 	ai_move, 0,	NULL,
1665 	ai_move, 0,	NULL,
1666 	ai_move, 0,	NULL,
1667 	ai_move, 0,	NULL,
1668 	ai_move, 0,	NULL,
1669 	ai_move, 0,	NULL,
1670 	ai_move, 0,	NULL,							// 246
1671 
1672 	ai_move, 0,	NULL,							// 247
1673 	ai_move, 0,	NULL,
1674 	ai_move, 0,	FireDeadRocket1,	// 249
1675 	ai_move, 0,	FireDeadRocket2,	// 250
1676 	ai_move, 0,	FireDeadRocket3,	// 251
1677 	ai_move, 0,	FireDeadRocket4,	// 252
1678 	ai_move, 0,	FireDeadRocket5,	// 253
1679 	ai_move, 0,	FireDeadRocket6,	// 254
1680 	ai_move, 0,	FireDeadRocket7,	// 255
1681 	ai_move, 0,	NULL,						  // 256
1682 
1683 	ai_move, 0,	FireDeadCannon1,  // 257
1684 	ai_move, 0,	FireDeadCannon2,	// 258
1685 	ai_move, 0,	NULL,
1686 	ai_move, 0,	NULL,
1687 	ai_move, 0,	NULL,
1688 	ai_move, 0,	NULL,
1689 	ai_move, 0,	NULL,
1690 	ai_move, 0,	FireDeadCannon3,	// 264
1691 	ai_move, 0,	NULL,
1692 	ai_move, 0,	NULL,							// 266
1693 
1694 	ai_move, 0,	NULL,							// 267
1695 	ai_move, 0,	NULL,
1696 	ai_move, 0,	NULL,
1697 	ai_move, 0,	NULL,
1698 	ai_move, 0,	NULL,
1699 	ai_move, 0,	NULL,
1700 	ai_move, 0,	NULL,
1701 	ai_move, 0,	NULL,
1702 	ai_move, 0,	NULL,
1703 	ai_move, 0,	NULL,							// 276
1704 
1705 	ai_move, 0,	NULL,							// 277
1706 	ai_move, 0,	NULL,
1707 	ai_move, 0,	NULL,
1708 	ai_move, 0,	NULL,
1709 	ai_move, 0,	FireDeadGrapple,	// 281
1710 };
1711 mmove_t zboss_move_death2 = {FRAME_die2Start, FRAME_die2End, zboss_frames_death2, zboss_dead};
1712 
1713 
zboss_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)1714 void zboss_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
1715 {
1716 	int		n;
1717 
1718 	if(self->laser)
1719 	{
1720 		G_FreeEdict(self->laser);
1721 		self->laser = NULL;
1722 	}
1723 
1724 // check for gib
1725 	if (self->health <= self->gib_health)
1726 	{
1727 		self->s.modelindex2 = 0;
1728 		self->s.modelindex3 = 0;
1729 
1730 		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
1731 		for (n= 0; n < 2; n++)
1732 			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
1733 		for (n= 0; n < 4; n++)
1734 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
1735 		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
1736 		self->deadflag = DEAD_DEAD;
1737 		return;
1738 	}
1739 
1740 	if (self->deadflag == DEAD_DEAD)
1741 		return;
1742 
1743 // regular death
1744 	self->deadflag = DEAD_DEAD;
1745 	self->takedamage = DAMAGE_YES;
1746 
1747 	// todo
1748 	if (random() < 0.5)
1749   {
1750 		gi.sound (self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0);
1751   	self->monsterinfo.currentmove = &zboss_move_death1;
1752   }
1753   else
1754   {
1755 		gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
1756   	self->monsterinfo.currentmove = &zboss_move_death2;
1757   }
1758 }
1759 
1760 
1761 /*
1762 ===
1763 End Death Stuff
1764 ===
1765 */
1766 
SP_monster_zboss_precache(void)1767 void SP_monster_zboss_precache(void)
1768 {
1769 	sound_pain1 = gi.soundindex ("monsters/bossz/bpain1.wav");
1770 	sound_pain2 = gi.soundindex ("monsters/bossz/bpain2.wav");
1771 	sound_pain3 = gi.soundindex ("monsters/bossz/bpain3.wav");
1772 	sound_die1 = gi.soundindex ("monsters/bossz/bdeth1.wav");
1773 	sound_die2 = gi.soundindex ("monsters/bossz/bdeth2.wav");
1774 	sound_hooklaunch = gi.soundindex("monsters/bossz/bhlaunch.wav");
1775 	sound_hookimpact = gi.soundindex("monsters/bossz/bhimpact.wav");
1776 	sound_hookfly	= gi.soundindex("monsters/bossz/bhfly.wav");
1777 	sound_sight = gi.soundindex("monsters/bossz/bsight1.wav");
1778 	sound_swing = gi.soundindex("monsters/bossz/bswing.wav");
1779 	sound_idle1 = gi.soundindex("monsters/bossz/bidle1.wav");
1780 	sound_idle2 = gi.soundindex("monsters/bossz/bidle2.wav");
1781 	sound_walk = gi.soundindex("monsters/bossz/bwalk.wav");
1782 	sound_raisegun = gi.soundindex("monsters/bossz/braisegun.wav");
1783 	sound_lowergun = gi.soundindex("monsters/bossz/blowergun.wav");
1784 	sound_switchattacks = gi.soundindex("monsters/bossz/bswitch.wav");
1785 	sound_plamsaballfly = gi.soundindex("monsters/bossz/bpbfly.wav");
1786 	sound_plamsaballexplode =	gi.soundindex("monsters/bossz/bpbexplode.wav");
1787 	sound_plamsaballfire = gi.soundindex("monsters/bossz/bpbfire.wav");
1788 	sound_taunt1 = gi.soundindex("monsters/bossz/btaunt1.wav");
1789 	sound_taunt2 = gi.soundindex("monsters/bossz/btaunt2.wav");
1790 	sound_taunt3 = gi.soundindex("monsters/bossz/btaunt3.wav");
1791 }
1792 
1793 
1794 /*QUAKED monster_zboss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
1795 */
SP_monster_zboss(edict_t * self)1796 void SP_monster_zboss (edict_t *self)
1797 {
1798 	if (deathmatch->value)
1799 	{
1800 		G_FreeEdict (self);
1801 		return;
1802 	}
1803 
1804 	SP_monster_zboss_precache();
1805 
1806 	// precache some models and sounds
1807 	gi.modelindex("sprites/plasma1.sp2");
1808 	gi.modelindex("models/objects/b_explode/tris.md2");
1809 	gi.soundindex("items/empnuke/emp_trg.wav");
1810 
1811 	self->s.modelindex = gi.modelindex ("models/monsters/bossz/mech/tris.md2");
1812 	self->s.modelindex2 = gi.modelindex ("models/monsters/bossz/pilot/tris.md2");
1813 	self->s.modelindex3 = gi.modelindex ("models/monsters/bossz/grapple/tris.md2");
1814 	VectorSet (self->mins, -32, -74, -30);
1815 	VectorSet (self->maxs, 32, 50, 74);
1816 	self->movetype = MOVETYPE_STEP;
1817 	self->solid = SOLID_BBOX;
1818 	self->monsterinfo.aiflags = AI_MONREDUCEDDAMAGE;
1819 	self->monsterinfo.reducedDamageAmount = 0.25;
1820 
1821 	if(skill->value == 0)
1822 	{
1823 		self->health = 3000;
1824 	}
1825 	else if(skill->value == 1)
1826 	{
1827 		self->health = 4500;
1828 	}
1829 	else if(skill->value == 2)
1830 	{
1831 		self->health = 6000;
1832 	}
1833 	else
1834 	{
1835 		self->health = 8000;
1836 	}
1837 
1838 	self->gib_health = -700;
1839 	self->mass = 1000;
1840 
1841 	self->pain = zboss_pain;
1842 	self->die = zboss_die;
1843 
1844 	self->monsterinfo.stand = zboss_stand;
1845 	self->monsterinfo.walk = zboss_walk;
1846 	self->monsterinfo.run = zboss_run;
1847 	self->monsterinfo.attack = zboss_attack;
1848 	self->monsterinfo.melee = zboss_melee;
1849 	self->monsterinfo.sight = zboss_sight;
1850 	self->monsterinfo.idle = possibleBossTaunt;
1851 
1852 	gi.linkentity (self);
1853 
1854 	self->monsterinfo.currentmove = &zboss_stand1;
1855 	self->monsterinfo.scale = MODEL_SCALE;
1856 
1857 	walkmonster_start (self);
1858 }
1859 
1860 
1861 
1862 /*QUAKED target_zboss_target
1863 */
1864 
trigger_zboss(edict_t * self,edict_t * other,edict_t * activator)1865 void trigger_zboss (edict_t *self, edict_t *other, edict_t *activator)
1866 {
1867 	edict_t	*boss = NULL;
1868 
1869 	while ((boss = G_Find (boss, FOFS(targetname), self->target)) != NULL)
1870 	{
1871 		if(boss->health > 0)
1872 		{
1873 			VectorCopy(	self->s.origin, boss->monsterinfo.shottarget );
1874 			boss->monsterinfo.aiflags |= AI_ONESHOTTARGET;
1875 			boss->monsterinfo.attack(boss);
1876 		}
1877   }
1878 }
1879 
1880 
SP_target_zboss_target(edict_t * self)1881 void SP_target_zboss_target(edict_t *self)
1882 {
1883 	if(!self->target)
1884 	{
1885 		gi.dprintf("target_zboss_target does not have a target");
1886 		G_FreeEdict (self);
1887 		return;
1888 	}
1889 
1890 	self->movetype = MOVETYPE_NONE;
1891 	self->svflags |= SVF_NOCLIENT;
1892 
1893 	self->solid = SOLID_NOT;
1894 	self->use = trigger_zboss;
1895 
1896 	gi.linkentity (self);
1897 }
1898