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 }