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