Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

m_tank.c (20036B)


      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 
     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 
     55 void tank_footstep (edict_t *self)
     56 {
     57 	gi.sound (self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
     58 }
     59 
     60 void tank_thud (edict_t *self)
     61 {
     62 	gi.sound (self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0);
     63 }
     64 
     65 void tank_windup (edict_t *self)
     66 {
     67 	gi.sound (self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
     68 }
     69 
     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 	
    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 
    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 
    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 
    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->value >= 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->value == 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 
    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 	AngleVectors (self->s.angles, forward, right, NULL);
    347 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
    348 
    349 	VectorCopy (self->enemy->s.origin, end);
    350 	end[2] += self->enemy->viewheight;
    351 	VectorSubtract (end, start, dir);
    352 
    353 	monster_fire_blaster (self, start, dir, 30, 800, flash_number, EF_BLASTER);
    354 }	
    355 
    356 void TankStrike (edict_t *self)
    357 {
    358 	gi.sound (self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0);
    359 }	
    360 
    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 	AngleVectors (self->s.angles, forward, right, NULL);
    377 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
    378 
    379 	VectorCopy (self->enemy->s.origin, vec);
    380 	vec[2] += self->enemy->viewheight;
    381 	VectorSubtract (vec, start, dir);
    382 	VectorNormalize (dir);
    383 
    384 	monster_fire_rocket (self, start, dir, 50, 550, flash_number);
    385 }	
    386 
    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 	AngleVectors (self->s.angles, forward, right, NULL);
    398 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
    399 
    400 	if (self->enemy)
    401 	{
    402 		VectorCopy (self->enemy->s.origin, vec);
    403 		vec[2] += self->enemy->viewheight;
    404 		VectorSubtract (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 	AngleVectors (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 
    467 void tank_reattack_blaster (edict_t *self)
    468 {
    469 	if (skill->value >= 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 
    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 
    636 void tank_refire_rocket (edict_t *self)
    637 {
    638 	// Only on hard or nightmare
    639 	if ( skill->value >= 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 
    650 void tank_doattack_rocket (edict_t *self)
    651 {
    652 	self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
    653 }
    654 
    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 	VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
    669 	range = VectorLength (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 
    706 void tank_dead (edict_t *self)
    707 {
    708 	VectorSet (self->mins, -16, -16, -16);
    709 	VectorSet (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 
    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 */
    792 void SP_monster_tank (edict_t *self)
    793 {
    794 	if (deathmatch->value)
    795 	{
    796 		G_FreeEdict (self);
    797 		return;
    798 	}
    799 
    800 	self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
    801 	VectorSet (self->mins, -32, -32, -16);
    802 	VectorSet (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 }