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