1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 /*
21 ==============================================================================
22
23 TANK
24
25 ==============================================================================
26 */
27
28 #include "g_local.h"
29 #include "m_tank.h"
30
31
32 void tank_refire_rocket (edict_t *self);
33 void tank_doattack_rocket (edict_t *self);
34 void tank_reattack_blaster (edict_t *self);
35
36 static int sound_thud;
37 static int sound_pain;
38 static int sound_idle;
39 static int sound_die;
40 static int sound_step;
41 static int sound_sight;
42 static int sound_windup;
43 static int sound_strike;
44
45 //
46 // misc
47 //
48
tank_sight(edict_t * self,edict_t * other)49 void tank_sight (edict_t *self, edict_t *other)
50 {
51 gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
52 }
53
54
tank_footstep(edict_t * self)55 void tank_footstep (edict_t *self)
56 {
57 gi.sound (self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
58 }
59
tank_thud(edict_t * self)60 void tank_thud (edict_t *self)
61 {
62 gi.sound (self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0);
63 }
64
tank_windup(edict_t * self)65 void tank_windup (edict_t *self)
66 {
67 gi.sound (self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
68 }
69
tank_idle(edict_t * self)70 void tank_idle (edict_t *self)
71 {
72 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
73 }
74
75
76 //
77 // stand
78 //
79
80 mframe_t tank_frames_stand []=
81 {
82 ai_stand, 0, NULL,
83 ai_stand, 0, NULL,
84 ai_stand, 0, NULL,
85 ai_stand, 0, NULL,
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,
96 ai_stand, 0, NULL,
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,
107 ai_stand, 0, NULL,
108 ai_stand, 0, NULL,
109 ai_stand, 0, NULL,
110 ai_stand, 0, NULL,
111 ai_stand, 0, NULL
112 };
113 mmove_t tank_move_stand = {FRAME_stand01, FRAME_stand30, tank_frames_stand, NULL};
114
tank_stand(edict_t * self)115 void tank_stand (edict_t *self)
116 {
117 self->monsterinfo.currentmove = &tank_move_stand;
118 }
119
120
121 //
122 // walk
123 //
124
125 void tank_walk (edict_t *self);
126
127 mframe_t tank_frames_start_walk [] =
128 {
129 ai_walk, 0, NULL,
130 ai_walk, 6, NULL,
131 ai_walk, 6, NULL,
132 ai_walk, 11, tank_footstep
133 };
134 mmove_t tank_move_start_walk = {FRAME_walk01, FRAME_walk04, tank_frames_start_walk, tank_walk};
135
136 mframe_t tank_frames_walk [] =
137 {
138 ai_walk, 4, NULL,
139 ai_walk, 5, NULL,
140 ai_walk, 3, NULL,
141 ai_walk, 2, NULL,
142 ai_walk, 5, NULL,
143 ai_walk, 5, NULL,
144 ai_walk, 4, NULL,
145 ai_walk, 4, tank_footstep,
146 ai_walk, 3, NULL,
147 ai_walk, 5, NULL,
148 ai_walk, 4, NULL,
149 ai_walk, 5, NULL,
150 ai_walk, 7, NULL,
151 ai_walk, 7, NULL,
152 ai_walk, 6, NULL,
153 ai_walk, 6, tank_footstep
154 };
155 mmove_t tank_move_walk = {FRAME_walk05, FRAME_walk20, tank_frames_walk, NULL};
156
157 mframe_t tank_frames_stop_walk [] =
158 {
159 ai_walk, 3, NULL,
160 ai_walk, 3, NULL,
161 ai_walk, 2, NULL,
162 ai_walk, 2, NULL,
163 ai_walk, 4, tank_footstep
164 };
165 mmove_t tank_move_stop_walk = {FRAME_walk21, FRAME_walk25, tank_frames_stop_walk, tank_stand};
166
tank_walk(edict_t * self)167 void tank_walk (edict_t *self)
168 {
169 self->monsterinfo.currentmove = &tank_move_walk;
170 }
171
172
173 //
174 // run
175 //
176
177 void tank_run (edict_t *self);
178
179 mframe_t tank_frames_start_run [] =
180 {
181 ai_run, 0, NULL,
182 ai_run, 6, NULL,
183 ai_run, 6, NULL,
184 ai_run, 11, tank_footstep
185 };
186 mmove_t tank_move_start_run = {FRAME_walk01, FRAME_walk04, tank_frames_start_run, tank_run};
187
188 mframe_t tank_frames_run [] =
189 {
190 ai_run, 4, NULL,
191 ai_run, 5, NULL,
192 ai_run, 3, NULL,
193 ai_run, 2, NULL,
194 ai_run, 5, NULL,
195 ai_run, 5, NULL,
196 ai_run, 4, NULL,
197 ai_run, 4, tank_footstep,
198 ai_run, 3, NULL,
199 ai_run, 5, NULL,
200 ai_run, 4, NULL,
201 ai_run, 5, NULL,
202 ai_run, 7, NULL,
203 ai_run, 7, NULL,
204 ai_run, 6, NULL,
205 ai_run, 6, tank_footstep
206 };
207 mmove_t tank_move_run = {FRAME_walk05, FRAME_walk20, tank_frames_run, NULL};
208
209 mframe_t tank_frames_stop_run [] =
210 {
211 ai_run, 3, NULL,
212 ai_run, 3, NULL,
213 ai_run, 2, NULL,
214 ai_run, 2, NULL,
215 ai_run, 4, tank_footstep
216 };
217 mmove_t tank_move_stop_run = {FRAME_walk21, FRAME_walk25, tank_frames_stop_run, tank_walk};
218
tank_run(edict_t * self)219 void tank_run (edict_t *self)
220 {
221 if (self->enemy && self->enemy->client)
222 self->monsterinfo.aiflags |= AI_BRUTAL;
223 else
224 self->monsterinfo.aiflags &= ~AI_BRUTAL;
225
226 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
227 {
228 self->monsterinfo.currentmove = &tank_move_stand;
229 return;
230 }
231
232 if (self->monsterinfo.currentmove == &tank_move_walk ||
233 self->monsterinfo.currentmove == &tank_move_start_run)
234 {
235 self->monsterinfo.currentmove = &tank_move_run;
236 }
237 else
238 {
239 self->monsterinfo.currentmove = &tank_move_start_run;
240 }
241 }
242
243 //
244 // pain
245 //
246
247 mframe_t tank_frames_pain1 [] =
248 {
249 ai_move, 0, NULL,
250 ai_move, 0, NULL,
251 ai_move, 0, NULL,
252 ai_move, 0, NULL
253 };
254 mmove_t tank_move_pain1 = {FRAME_pain101, FRAME_pain104, tank_frames_pain1, tank_run};
255
256 mframe_t tank_frames_pain2 [] =
257 {
258 ai_move, 0, NULL,
259 ai_move, 0, NULL,
260 ai_move, 0, NULL,
261 ai_move, 0, NULL,
262 ai_move, 0, NULL
263 };
264 mmove_t tank_move_pain2 = {FRAME_pain201, FRAME_pain205, tank_frames_pain2, tank_run};
265
266 mframe_t tank_frames_pain3 [] =
267 {
268 ai_move, -7, NULL,
269 ai_move, 0, NULL,
270 ai_move, 0, NULL,
271 ai_move, 0, NULL,
272 ai_move, 2, NULL,
273 ai_move, 0, NULL,
274 ai_move, 0, NULL,
275 ai_move, 3, NULL,
276 ai_move, 0, NULL,
277 ai_move, 2, NULL,
278 ai_move, 0, NULL,
279 ai_move, 0, NULL,
280 ai_move, 0, NULL,
281 ai_move, 0, NULL,
282 ai_move, 0, NULL,
283 ai_move, 0, tank_footstep
284 };
285 mmove_t tank_move_pain3 = {FRAME_pain301, FRAME_pain316, tank_frames_pain3, tank_run};
286
287
tank_pain(edict_t * self,edict_t * other,float kick,int damage)288 void tank_pain (edict_t *self, edict_t *other, float kick, int damage)
289 {
290 if (self->health < (self->max_health / 2))
291 self->s.skinNum |= 1;
292
293 if (damage <= 10)
294 return;
295
296 if (level.time < self->pain_debounce_time)
297 return;
298
299 if (damage <= 30)
300 if (random() > 0.2)
301 return;
302
303 // If hard or nightmare, don't go into pain while attacking
304 if ( skill->floatVal >= 2)
305 {
306 if ( (self->s.frame >= FRAME_attak301) && (self->s.frame <= FRAME_attak330) )
307 return;
308 if ( (self->s.frame >= FRAME_attak101) && (self->s.frame <= FRAME_attak116) )
309 return;
310 }
311
312 self->pain_debounce_time = level.time + 3;
313 gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
314
315 if (skill->floatVal == 3)
316 return; // no pain anims in nightmare
317
318 if (damage <= 30)
319 self->monsterinfo.currentmove = &tank_move_pain1;
320 else if (damage <= 60)
321 self->monsterinfo.currentmove = &tank_move_pain2;
322 else
323 self->monsterinfo.currentmove = &tank_move_pain3;
324 };
325
326
327 //
328 // attacks
329 //
330
TankBlaster(edict_t * self)331 void TankBlaster (edict_t *self)
332 {
333 vec3_t forward, right;
334 vec3_t start;
335 vec3_t end;
336 vec3_t dir;
337 int flash_number;
338
339 if (self->s.frame == FRAME_attak110)
340 flash_number = MZ2_TANK_BLASTER_1;
341 else if (self->s.frame == FRAME_attak113)
342 flash_number = MZ2_TANK_BLASTER_2;
343 else // (self->s.frame == FRAME_attak116)
344 flash_number = MZ2_TANK_BLASTER_3;
345
346 Angles_Vectors (self->s.angles, forward, right, NULL);
347 G_ProjectSource (self->s.origin, dumb_and_hacky_monster_MuzzFlashOffset[flash_number], forward, right, start);
348
349 Vec3Copy (self->enemy->s.origin, end);
350 end[2] += self->enemy->viewheight;
351 Vec3Subtract (end, start, dir);
352
353 monster_fire_blaster (self, start, dir, 30, 800, flash_number, EF_BLASTER);
354 }
355
TankStrike(edict_t * self)356 void TankStrike (edict_t *self)
357 {
358 gi.sound (self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0);
359 }
360
TankRocket(edict_t * self)361 void TankRocket (edict_t *self)
362 {
363 vec3_t forward, right;
364 vec3_t start;
365 vec3_t dir;
366 vec3_t vec;
367 int flash_number;
368
369 if (self->s.frame == FRAME_attak324)
370 flash_number = MZ2_TANK_ROCKET_1;
371 else if (self->s.frame == FRAME_attak327)
372 flash_number = MZ2_TANK_ROCKET_2;
373 else // (self->s.frame == FRAME_attak330)
374 flash_number = MZ2_TANK_ROCKET_3;
375
376 Angles_Vectors (self->s.angles, forward, right, NULL);
377 G_ProjectSource (self->s.origin, dumb_and_hacky_monster_MuzzFlashOffset[flash_number], forward, right, start);
378
379 Vec3Copy (self->enemy->s.origin, vec);
380 vec[2] += self->enemy->viewheight;
381 Vec3Subtract (vec, start, dir);
382 VectorNormalizef (dir, dir);
383
384 monster_fire_rocket (self, start, dir, 50, 550, flash_number);
385 }
386
TankMachineGun(edict_t * self)387 void TankMachineGun (edict_t *self)
388 {
389 vec3_t dir;
390 vec3_t vec;
391 vec3_t start;
392 vec3_t forward, right;
393 int flash_number;
394
395 flash_number = MZ2_TANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak406);
396
397 Angles_Vectors (self->s.angles, forward, right, NULL);
398 G_ProjectSource (self->s.origin, dumb_and_hacky_monster_MuzzFlashOffset[flash_number], forward, right, start);
399
400 if (self->enemy)
401 {
402 Vec3Copy (self->enemy->s.origin, vec);
403 vec[2] += self->enemy->viewheight;
404 Vec3Subtract (vec, start, vec);
405 VecToAngles (vec, vec);
406 dir[0] = vec[0];
407 }
408 else
409 {
410 dir[0] = 0;
411 }
412 if (self->s.frame <= FRAME_attak415)
413 dir[1] = self->s.angles[1] - 8 * (self->s.frame - FRAME_attak411);
414 else
415 dir[1] = self->s.angles[1] + 8 * (self->s.frame - FRAME_attak419);
416 dir[2] = 0;
417
418 Angles_Vectors (dir, forward, NULL, NULL);
419
420 monster_fire_bullet (self, start, forward, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
421 }
422
423
424 mframe_t tank_frames_attack_blast [] =
425 {
426 ai_charge, 0, NULL,
427 ai_charge, 0, NULL,
428 ai_charge, 0, NULL,
429 ai_charge, 0, NULL,
430 ai_charge, -1, NULL,
431 ai_charge, -2, NULL,
432 ai_charge, -1, NULL,
433 ai_charge, -1, NULL,
434 ai_charge, 0, NULL,
435 ai_charge, 0, TankBlaster, // 10
436 ai_charge, 0, NULL,
437 ai_charge, 0, NULL,
438 ai_charge, 0, TankBlaster,
439 ai_charge, 0, NULL,
440 ai_charge, 0, NULL,
441 ai_charge, 0, TankBlaster // 16
442 };
443 mmove_t tank_move_attack_blast = {FRAME_attak101, FRAME_attak116, tank_frames_attack_blast, tank_reattack_blaster};
444
445 mframe_t tank_frames_reattack_blast [] =
446 {
447 ai_charge, 0, NULL,
448 ai_charge, 0, NULL,
449 ai_charge, 0, TankBlaster,
450 ai_charge, 0, NULL,
451 ai_charge, 0, NULL,
452 ai_charge, 0, TankBlaster // 16
453 };
454 mmove_t tank_move_reattack_blast = {FRAME_attak111, FRAME_attak116, tank_frames_reattack_blast, tank_reattack_blaster};
455
456 mframe_t tank_frames_attack_post_blast [] =
457 {
458 ai_move, 0, NULL, // 17
459 ai_move, 0, NULL,
460 ai_move, 2, NULL,
461 ai_move, 3, NULL,
462 ai_move, 2, NULL,
463 ai_move, -2, tank_footstep // 22
464 };
465 mmove_t tank_move_attack_post_blast = {FRAME_attak117, FRAME_attak122, tank_frames_attack_post_blast, tank_run};
466
tank_reattack_blaster(edict_t * self)467 void tank_reattack_blaster (edict_t *self)
468 {
469 if (skill->floatVal >= 2)
470 if (visible (self, self->enemy))
471 if (self->enemy->health > 0)
472 if (random() <= 0.6)
473 {
474 self->monsterinfo.currentmove = &tank_move_reattack_blast;
475 return;
476 }
477 self->monsterinfo.currentmove = &tank_move_attack_post_blast;
478 }
479
480
tank_poststrike(edict_t * self)481 void tank_poststrike (edict_t *self)
482 {
483 self->enemy = NULL;
484 tank_run (self);
485 }
486
487 mframe_t tank_frames_attack_strike [] =
488 {
489 ai_move, 3, NULL,
490 ai_move, 2, NULL,
491 ai_move, 2, NULL,
492 ai_move, 1, NULL,
493 ai_move, 6, NULL,
494 ai_move, 7, NULL,
495 ai_move, 9, tank_footstep,
496 ai_move, 2, NULL,
497 ai_move, 1, NULL,
498 ai_move, 2, NULL,
499 ai_move, 2, tank_footstep,
500 ai_move, 2, NULL,
501 ai_move, 0, NULL,
502 ai_move, 0, NULL,
503 ai_move, 0, NULL,
504 ai_move, 0, NULL,
505 ai_move, -2, NULL,
506 ai_move, -2, NULL,
507 ai_move, 0, tank_windup,
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, TankStrike,
515 ai_move, 0, NULL,
516 ai_move, -1, NULL,
517 ai_move, -1, NULL,
518 ai_move, -1, NULL,
519 ai_move, -1, NULL,
520 ai_move, -1, NULL,
521 ai_move, -3, NULL,
522 ai_move, -10, NULL,
523 ai_move, -10, NULL,
524 ai_move, -2, NULL,
525 ai_move, -3, NULL,
526 ai_move, -2, tank_footstep
527 };
528 mmove_t tank_move_attack_strike = {FRAME_attak201, FRAME_attak238, tank_frames_attack_strike, tank_poststrike};
529
530 mframe_t tank_frames_attack_pre_rocket [] =
531 {
532 ai_charge, 0, NULL,
533 ai_charge, 0, NULL,
534 ai_charge, 0, NULL,
535 ai_charge, 0, NULL,
536 ai_charge, 0, NULL,
537 ai_charge, 0, NULL,
538 ai_charge, 0, NULL,
539 ai_charge, 0, NULL,
540 ai_charge, 0, NULL,
541 ai_charge, 0, NULL, // 10
542
543 ai_charge, 0, NULL,
544 ai_charge, 1, NULL,
545 ai_charge, 2, NULL,
546 ai_charge, 7, NULL,
547 ai_charge, 7, NULL,
548 ai_charge, 7, tank_footstep,
549 ai_charge, 0, NULL,
550 ai_charge, 0, NULL,
551 ai_charge, 0, NULL,
552 ai_charge, 0, NULL, // 20
553
554 ai_charge, -3, NULL
555 };
556 mmove_t tank_move_attack_pre_rocket = {FRAME_attak301, FRAME_attak321, tank_frames_attack_pre_rocket, tank_doattack_rocket};
557
558 mframe_t tank_frames_attack_fire_rocket [] =
559 {
560 ai_charge, -3, NULL, // Loop Start 22
561 ai_charge, 0, NULL,
562 ai_charge, 0, TankRocket, // 24
563 ai_charge, 0, NULL,
564 ai_charge, 0, NULL,
565 ai_charge, 0, TankRocket,
566 ai_charge, 0, NULL,
567 ai_charge, 0, NULL,
568 ai_charge, -1, TankRocket // 30 Loop End
569 };
570 mmove_t tank_move_attack_fire_rocket = {FRAME_attak322, FRAME_attak330, tank_frames_attack_fire_rocket, tank_refire_rocket};
571
572 mframe_t tank_frames_attack_post_rocket [] =
573 {
574 ai_charge, 0, NULL, // 31
575 ai_charge, -1, NULL,
576 ai_charge, -1, NULL,
577 ai_charge, 0, NULL,
578 ai_charge, 2, NULL,
579 ai_charge, 3, NULL,
580 ai_charge, 4, NULL,
581 ai_charge, 2, NULL,
582 ai_charge, 0, NULL,
583 ai_charge, 0, NULL, // 40
584
585 ai_charge, 0, NULL,
586 ai_charge, -9, NULL,
587 ai_charge, -8, NULL,
588 ai_charge, -7, NULL,
589 ai_charge, -1, NULL,
590 ai_charge, -1, tank_footstep,
591 ai_charge, 0, NULL,
592 ai_charge, 0, NULL,
593 ai_charge, 0, NULL,
594 ai_charge, 0, NULL, // 50
595
596 ai_charge, 0, NULL,
597 ai_charge, 0, NULL,
598 ai_charge, 0, NULL
599 };
600 mmove_t tank_move_attack_post_rocket = {FRAME_attak331, FRAME_attak353, tank_frames_attack_post_rocket, tank_run};
601
602 mframe_t tank_frames_attack_chain [] =
603 {
604 ai_charge, 0, NULL,
605 ai_charge, 0, NULL,
606 ai_charge, 0, NULL,
607 ai_charge, 0, NULL,
608 ai_charge, 0, NULL,
609 NULL, 0, TankMachineGun,
610 NULL, 0, TankMachineGun,
611 NULL, 0, TankMachineGun,
612 NULL, 0, TankMachineGun,
613 NULL, 0, TankMachineGun,
614 NULL, 0, TankMachineGun,
615 NULL, 0, TankMachineGun,
616 NULL, 0, TankMachineGun,
617 NULL, 0, TankMachineGun,
618 NULL, 0, TankMachineGun,
619 NULL, 0, TankMachineGun,
620 NULL, 0, TankMachineGun,
621 NULL, 0, TankMachineGun,
622 NULL, 0, TankMachineGun,
623 NULL, 0, TankMachineGun,
624 NULL, 0, TankMachineGun,
625 NULL, 0, TankMachineGun,
626 NULL, 0, TankMachineGun,
627 NULL, 0, TankMachineGun,
628 ai_charge, 0, NULL,
629 ai_charge, 0, NULL,
630 ai_charge, 0, NULL,
631 ai_charge, 0, NULL,
632 ai_charge, 0, NULL
633 };
634 mmove_t tank_move_attack_chain = {FRAME_attak401, FRAME_attak429, tank_frames_attack_chain, tank_run};
635
tank_refire_rocket(edict_t * self)636 void tank_refire_rocket (edict_t *self)
637 {
638 // Only on hard or nightmare
639 if ( skill->floatVal >= 2 )
640 if (self->enemy->health > 0)
641 if (visible(self, self->enemy) )
642 if (random() <= 0.4)
643 {
644 self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
645 return;
646 }
647 self->monsterinfo.currentmove = &tank_move_attack_post_rocket;
648 }
649
tank_doattack_rocket(edict_t * self)650 void tank_doattack_rocket (edict_t *self)
651 {
652 self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
653 }
654
tank_attack(edict_t * self)655 void tank_attack(edict_t *self)
656 {
657 vec3_t vec;
658 float range;
659 float r;
660
661 if (self->enemy->health < 0)
662 {
663 self->monsterinfo.currentmove = &tank_move_attack_strike;
664 self->monsterinfo.aiflags &= ~AI_BRUTAL;
665 return;
666 }
667
668 Vec3Subtract (self->enemy->s.origin, self->s.origin, vec);
669 range = Vec3Length (vec);
670
671 r = random();
672
673 if (range <= 125)
674 {
675 if (r < 0.4)
676 self->monsterinfo.currentmove = &tank_move_attack_chain;
677 else
678 self->monsterinfo.currentmove = &tank_move_attack_blast;
679 }
680 else if (range <= 250)
681 {
682 if (r < 0.5)
683 self->monsterinfo.currentmove = &tank_move_attack_chain;
684 else
685 self->monsterinfo.currentmove = &tank_move_attack_blast;
686 }
687 else
688 {
689 if (r < 0.33)
690 self->monsterinfo.currentmove = &tank_move_attack_chain;
691 else if (r < 0.66)
692 {
693 self->monsterinfo.currentmove = &tank_move_attack_pre_rocket;
694 self->pain_debounce_time = level.time + 5.0; // no pain for a while
695 }
696 else
697 self->monsterinfo.currentmove = &tank_move_attack_blast;
698 }
699 }
700
701
702 //
703 // death
704 //
705
tank_dead(edict_t * self)706 void tank_dead (edict_t *self)
707 {
708 Vec3Set (self->mins, -16, -16, -16);
709 Vec3Set (self->maxs, 16, 16, -0);
710 self->movetype = MOVETYPE_TOSS;
711 self->svFlags |= SVF_DEADMONSTER;
712 self->nextthink = 0;
713 gi.linkentity (self);
714 }
715
716 mframe_t tank_frames_death1 [] =
717 {
718 ai_move, -7, NULL,
719 ai_move, -2, NULL,
720 ai_move, -2, NULL,
721 ai_move, 1, NULL,
722 ai_move, 3, NULL,
723 ai_move, 6, NULL,
724 ai_move, 1, NULL,
725 ai_move, 1, NULL,
726 ai_move, 2, NULL,
727 ai_move, 0, NULL,
728 ai_move, 0, NULL,
729 ai_move, 0, NULL,
730 ai_move, -2, NULL,
731 ai_move, 0, NULL,
732 ai_move, 0, NULL,
733 ai_move, -3, NULL,
734 ai_move, 0, NULL,
735 ai_move, 0, NULL,
736 ai_move, 0, NULL,
737 ai_move, 0, NULL,
738 ai_move, 0, NULL,
739 ai_move, 0, NULL,
740 ai_move, -4, NULL,
741 ai_move, -6, NULL,
742 ai_move, -4, NULL,
743 ai_move, -5, NULL,
744 ai_move, -7, NULL,
745 ai_move, -15, tank_thud,
746 ai_move, -5, NULL,
747 ai_move, 0, NULL,
748 ai_move, 0, NULL,
749 ai_move, 0, NULL
750 };
751 mmove_t tank_move_death = {FRAME_death101, FRAME_death132, tank_frames_death1, tank_dead};
752
tank_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)753 void tank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
754 {
755 int n;
756
757 // check for gib
758 if (self->health <= self->gib_health)
759 {
760 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
761 for (n= 0; n < 1 /*4*/; n++)
762 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
763 for (n= 0; n < 4; n++)
764 ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
765 ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
766 ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
767 self->deadflag = DEAD_DEAD;
768 return;
769 }
770
771 if (self->deadflag == DEAD_DEAD)
772 return;
773
774 // regular death
775 gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
776 self->deadflag = DEAD_DEAD;
777 self->takedamage = DAMAGE_YES;
778
779 self->monsterinfo.currentmove = &tank_move_death;
780
781 }
782
783
784 //
785 // monster_tank
786 //
787
788 /*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
789 */
790 /*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
791 */
SP_monster_tank(edict_t * self)792 void SP_monster_tank (edict_t *self)
793 {
794 if (deathmatch->floatVal)
795 {
796 G_FreeEdict (self);
797 return;
798 }
799
800 self->s.modelIndex = gi.modelindex ("models/monsters/tank/tris.md2");
801 Vec3Set (self->mins, -32, -32, -16);
802 Vec3Set (self->maxs, 32, 32, 72);
803 self->movetype = MOVETYPE_STEP;
804 self->solid = SOLID_BBOX;
805
806 sound_pain = gi.soundindex ("tank/tnkpain2.wav");
807 sound_thud = gi.soundindex ("tank/tnkdeth2.wav");
808 sound_idle = gi.soundindex ("tank/tnkidle1.wav");
809 sound_die = gi.soundindex ("tank/death.wav");
810 sound_step = gi.soundindex ("tank/step.wav");
811 sound_windup = gi.soundindex ("tank/tnkatck4.wav");
812 sound_strike = gi.soundindex ("tank/tnkatck5.wav");
813 sound_sight = gi.soundindex ("tank/sight1.wav");
814
815 gi.soundindex ("tank/tnkatck1.wav");
816 gi.soundindex ("tank/tnkatk2a.wav");
817 gi.soundindex ("tank/tnkatk2b.wav");
818 gi.soundindex ("tank/tnkatk2c.wav");
819 gi.soundindex ("tank/tnkatk2d.wav");
820 gi.soundindex ("tank/tnkatk2e.wav");
821 gi.soundindex ("tank/tnkatck3.wav");
822
823 if (strcmp(self->classname, "monster_tank_commander") == 0)
824 {
825 self->health = 1000;
826 self->gib_health = -225;
827 }
828 else
829 {
830 self->health = 750;
831 self->gib_health = -200;
832 }
833
834 self->mass = 500;
835
836 self->pain = tank_pain;
837 self->die = tank_die;
838 self->monsterinfo.stand = tank_stand;
839 self->monsterinfo.walk = tank_walk;
840 self->monsterinfo.run = tank_run;
841 self->monsterinfo.dodge = NULL;
842 self->monsterinfo.attack = tank_attack;
843 self->monsterinfo.melee = NULL;
844 self->monsterinfo.sight = tank_sight;
845 self->monsterinfo.idle = tank_idle;
846
847 gi.linkentity (self);
848
849 self->monsterinfo.currentmove = &tank_move_stand;
850 self->monsterinfo.scale = MODEL_SCALE;
851
852 walkmonster_start(self);
853
854 if (strcmp (self->classname, "monster_tank_commander") == 0)
855 self->s.skinNum = 2;
856 }
857