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