|
|
1.1 ! root 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: ! 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: ! 36: void tank_footstep (edict_t *self) ! 37: { ! 38: gi.sound (self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0); ! 39: } ! 40: ! 41: void tank_thud (edict_t *self) ! 42: { ! 43: gi.sound (self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0); ! 44: } ! 45: ! 46: void tank_windup (edict_t *self) ! 47: { ! 48: gi.sound (self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0); ! 49: } ! 50: ! 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: ! 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: ! 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: ! 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: ! 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: ! 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, 30, 800, flash_number, EF_BLASTER); ! 335: } ! 336: ! 337: void TankStrike (edict_t *self) ! 338: { ! 339: gi.sound (self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0); ! 340: } ! 341: ! 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: ! 350: if (self->s.frame == FRAME_attak324) ! 351: flash_number = MZ2_TANK_ROCKET_1; ! 352: else if (self->s.frame == FRAME_attak327) ! 353: flash_number = MZ2_TANK_ROCKET_2; ! 354: else // (self->s.frame == FRAME_attak330) ! 355: flash_number = MZ2_TANK_ROCKET_3; ! 356: ! 357: AngleVectors (self->s.angles, forward, right, NULL); ! 358: G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); ! 359: ! 360: VectorCopy (self->enemy->s.origin, vec); ! 361: vec[2] += self->enemy->viewheight; ! 362: VectorSubtract (vec, start, dir); ! 363: VectorNormalize (dir); ! 364: ! 365: monster_fire_rocket (self, start, dir, 50, 550, flash_number); ! 366: } ! 367: ! 368: void TankMachineGun (edict_t *self) ! 369: { ! 370: vec3_t dir; ! 371: vec3_t vec; ! 372: vec3_t start; ! 373: vec3_t forward, right; ! 374: int flash_number; ! 375: ! 376: flash_number = MZ2_TANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak406); ! 377: ! 378: AngleVectors (self->s.angles, forward, right, NULL); ! 379: G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); ! 380: ! 381: if (self->enemy) ! 382: { ! 383: VectorCopy (self->enemy->s.origin, vec); ! 384: vec[2] += self->enemy->viewheight; ! 385: VectorSubtract (vec, start, vec); ! 386: vectoangles (vec, vec); ! 387: dir[0] = vec[0]; ! 388: } ! 389: else ! 390: { ! 391: dir[0] = 0; ! 392: } ! 393: if (self->s.frame <= FRAME_attak415) ! 394: dir[1] = self->s.angles[1] - 8 * (self->s.frame - FRAME_attak411); ! 395: else ! 396: dir[1] = self->s.angles[1] + 8 * (self->s.frame - FRAME_attak419); ! 397: dir[2] = 0; ! 398: ! 399: AngleVectors (dir, forward, NULL, NULL); ! 400: ! 401: monster_fire_bullet (self, start, forward, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number); ! 402: } ! 403: ! 404: ! 405: mframe_t tank_frames_attack_blast [] = ! 406: { ! 407: ai_charge, 0, NULL, ! 408: ai_charge, 0, NULL, ! 409: ai_charge, 0, NULL, ! 410: ai_charge, 0, NULL, ! 411: ai_charge, -1, NULL, ! 412: ai_charge, -2, NULL, ! 413: ai_charge, -1, NULL, ! 414: ai_charge, -1, NULL, ! 415: ai_charge, 0, NULL, ! 416: ai_charge, 0, TankBlaster, // 10 ! 417: ai_charge, 0, NULL, ! 418: ai_charge, 0, NULL, ! 419: ai_charge, 0, TankBlaster, ! 420: ai_charge, 0, NULL, ! 421: ai_charge, 0, NULL, ! 422: ai_charge, 0, TankBlaster // 16 ! 423: }; ! 424: mmove_t tank_move_attack_blast = {FRAME_attak101, FRAME_attak116, tank_frames_attack_blast, tank_reattack_blaster}; ! 425: ! 426: mframe_t tank_frames_reattack_blast [] = ! 427: { ! 428: ai_charge, 0, NULL, ! 429: ai_charge, 0, NULL, ! 430: ai_charge, 0, TankBlaster, ! 431: ai_charge, 0, NULL, ! 432: ai_charge, 0, NULL, ! 433: ai_charge, 0, TankBlaster // 16 ! 434: }; ! 435: mmove_t tank_move_reattack_blast = {FRAME_attak111, FRAME_attak116, tank_frames_reattack_blast, tank_reattack_blaster}; ! 436: ! 437: mframe_t tank_frames_attack_post_blast [] = ! 438: { ! 439: ai_move, 0, NULL, // 17 ! 440: ai_move, 0, NULL, ! 441: ai_move, 2, NULL, ! 442: ai_move, 3, NULL, ! 443: ai_move, 2, NULL, ! 444: ai_move, -2, tank_footstep // 22 ! 445: }; ! 446: mmove_t tank_move_attack_post_blast = {FRAME_attak117, FRAME_attak122, tank_frames_attack_post_blast, tank_run}; ! 447: ! 448: void tank_reattack_blaster (edict_t *self) ! 449: { ! 450: if (skill->value >= 2) ! 451: if (visible (self, self->enemy)) ! 452: if (self->enemy->health > 0) ! 453: if (random() <= 0.6) ! 454: { ! 455: self->monsterinfo.currentmove = &tank_move_reattack_blast; ! 456: return; ! 457: } ! 458: self->monsterinfo.currentmove = &tank_move_attack_post_blast; ! 459: } ! 460: ! 461: ! 462: void tank_poststrike (edict_t *self) ! 463: { ! 464: self->enemy = NULL; ! 465: tank_run (self); ! 466: } ! 467: ! 468: mframe_t tank_frames_attack_strike [] = ! 469: { ! 470: ai_move, 3, NULL, ! 471: ai_move, 2, NULL, ! 472: ai_move, 2, NULL, ! 473: ai_move, 1, NULL, ! 474: ai_move, 6, NULL, ! 475: ai_move, 7, NULL, ! 476: ai_move, 9, tank_footstep, ! 477: ai_move, 2, NULL, ! 478: ai_move, 1, NULL, ! 479: ai_move, 2, NULL, ! 480: ai_move, 2, tank_footstep, ! 481: ai_move, 2, NULL, ! 482: ai_move, 0, NULL, ! 483: ai_move, 0, NULL, ! 484: ai_move, 0, NULL, ! 485: ai_move, 0, NULL, ! 486: ai_move, -2, NULL, ! 487: ai_move, -2, NULL, ! 488: ai_move, 0, tank_windup, ! 489: ai_move, 0, NULL, ! 490: ai_move, 0, NULL, ! 491: ai_move, 0, NULL, ! 492: ai_move, 0, NULL, ! 493: ai_move, 0, NULL, ! 494: ai_move, 0, NULL, ! 495: ai_move, 0, TankStrike, ! 496: ai_move, 0, NULL, ! 497: ai_move, -1, NULL, ! 498: ai_move, -1, NULL, ! 499: ai_move, -1, NULL, ! 500: ai_move, -1, NULL, ! 501: ai_move, -1, NULL, ! 502: ai_move, -3, NULL, ! 503: ai_move, -10, NULL, ! 504: ai_move, -10, NULL, ! 505: ai_move, -2, NULL, ! 506: ai_move, -3, NULL, ! 507: ai_move, -2, tank_footstep ! 508: }; ! 509: mmove_t tank_move_attack_strike = {FRAME_attak201, FRAME_attak238, tank_frames_attack_strike, tank_poststrike}; ! 510: ! 511: mframe_t tank_frames_attack_pre_rocket [] = ! 512: { ! 513: ai_charge, 0, NULL, ! 514: ai_charge, 0, NULL, ! 515: ai_charge, 0, NULL, ! 516: ai_charge, 0, NULL, ! 517: ai_charge, 0, NULL, ! 518: ai_charge, 0, NULL, ! 519: ai_charge, 0, NULL, ! 520: ai_charge, 0, NULL, ! 521: ai_charge, 0, NULL, ! 522: ai_charge, 0, NULL, // 10 ! 523: ! 524: ai_charge, 0, NULL, ! 525: ai_charge, 1, NULL, ! 526: ai_charge, 2, NULL, ! 527: ai_charge, 7, NULL, ! 528: ai_charge, 7, NULL, ! 529: ai_charge, 7, tank_footstep, ! 530: ai_charge, 0, NULL, ! 531: ai_charge, 0, NULL, ! 532: ai_charge, 0, NULL, ! 533: ai_charge, 0, NULL, // 20 ! 534: ! 535: ai_charge, -3, NULL ! 536: }; ! 537: mmove_t tank_move_attack_pre_rocket = {FRAME_attak301, FRAME_attak321, tank_frames_attack_pre_rocket, tank_doattack_rocket}; ! 538: ! 539: mframe_t tank_frames_attack_fire_rocket [] = ! 540: { ! 541: ai_charge, -3, NULL, // Loop Start 22 ! 542: ai_charge, 0, NULL, ! 543: ai_charge, 0, TankRocket, // 24 ! 544: ai_charge, 0, NULL, ! 545: ai_charge, 0, NULL, ! 546: ai_charge, 0, TankRocket, ! 547: ai_charge, 0, NULL, ! 548: ai_charge, 0, NULL, ! 549: ai_charge, -1, TankRocket // 30 Loop End ! 550: }; ! 551: mmove_t tank_move_attack_fire_rocket = {FRAME_attak322, FRAME_attak330, tank_frames_attack_fire_rocket, tank_refire_rocket}; ! 552: ! 553: mframe_t tank_frames_attack_post_rocket [] = ! 554: { ! 555: ai_charge, 0, NULL, // 31 ! 556: ai_charge, -1, NULL, ! 557: ai_charge, -1, NULL, ! 558: ai_charge, 0, NULL, ! 559: ai_charge, 2, NULL, ! 560: ai_charge, 3, NULL, ! 561: ai_charge, 4, NULL, ! 562: ai_charge, 2, NULL, ! 563: ai_charge, 0, NULL, ! 564: ai_charge, 0, NULL, // 40 ! 565: ! 566: ai_charge, 0, NULL, ! 567: ai_charge, -9, NULL, ! 568: ai_charge, -8, NULL, ! 569: ai_charge, -7, NULL, ! 570: ai_charge, -1, NULL, ! 571: ai_charge, -1, tank_footstep, ! 572: ai_charge, 0, NULL, ! 573: ai_charge, 0, NULL, ! 574: ai_charge, 0, NULL, ! 575: ai_charge, 0, NULL, // 50 ! 576: ! 577: ai_charge, 0, NULL, ! 578: ai_charge, 0, NULL, ! 579: ai_charge, 0, NULL ! 580: }; ! 581: mmove_t tank_move_attack_post_rocket = {FRAME_attak331, FRAME_attak353, tank_frames_attack_post_rocket, tank_run}; ! 582: ! 583: mframe_t tank_frames_attack_chain [] = ! 584: { ! 585: ai_charge, 0, NULL, ! 586: ai_charge, 0, NULL, ! 587: ai_charge, 0, NULL, ! 588: ai_charge, 0, NULL, ! 589: ai_charge, 0, NULL, ! 590: NULL, 0, TankMachineGun, ! 591: NULL, 0, TankMachineGun, ! 592: NULL, 0, TankMachineGun, ! 593: NULL, 0, TankMachineGun, ! 594: NULL, 0, TankMachineGun, ! 595: NULL, 0, TankMachineGun, ! 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: ai_charge, 0, NULL, ! 610: ai_charge, 0, NULL, ! 611: ai_charge, 0, NULL, ! 612: ai_charge, 0, NULL, ! 613: ai_charge, 0, NULL ! 614: }; ! 615: mmove_t tank_move_attack_chain = {FRAME_attak401, FRAME_attak429, tank_frames_attack_chain, tank_run}; ! 616: ! 617: void tank_refire_rocket (edict_t *self) ! 618: { ! 619: // Only on hard or nightmare ! 620: if ( skill->value >= 2 ) ! 621: if (self->enemy->health > 0) ! 622: if (visible(self, self->enemy) ) ! 623: if (random() <= 0.4) ! 624: { ! 625: self->monsterinfo.currentmove = &tank_move_attack_fire_rocket; ! 626: return; ! 627: } ! 628: self->monsterinfo.currentmove = &tank_move_attack_post_rocket; ! 629: } ! 630: ! 631: void tank_doattack_rocket (edict_t *self) ! 632: { ! 633: self->monsterinfo.currentmove = &tank_move_attack_fire_rocket; ! 634: } ! 635: ! 636: void tank_attack(edict_t *self) ! 637: { ! 638: vec3_t vec; ! 639: float range; ! 640: float r; ! 641: ! 642: if (self->enemy->health < 0) ! 643: { ! 644: self->monsterinfo.currentmove = &tank_move_attack_strike; ! 645: self->monsterinfo.aiflags &= ~AI_BRUTAL; ! 646: return; ! 647: } ! 648: ! 649: VectorSubtract (self->enemy->s.origin, self->s.origin, vec); ! 650: range = VectorLength (vec); ! 651: ! 652: r = random(); ! 653: ! 654: if (range <= 125) ! 655: { ! 656: if (r < 0.4) ! 657: self->monsterinfo.currentmove = &tank_move_attack_chain; ! 658: else ! 659: self->monsterinfo.currentmove = &tank_move_attack_blast; ! 660: } ! 661: else if (range <= 250) ! 662: { ! 663: if (r < 0.5) ! 664: self->monsterinfo.currentmove = &tank_move_attack_chain; ! 665: else ! 666: self->monsterinfo.currentmove = &tank_move_attack_blast; ! 667: } ! 668: else ! 669: { ! 670: if (r < 0.33) ! 671: self->monsterinfo.currentmove = &tank_move_attack_chain; ! 672: else if (r < 0.66) ! 673: { ! 674: self->monsterinfo.currentmove = &tank_move_attack_pre_rocket; ! 675: self->pain_debounce_time = level.time + 5.0; // no pain for a while ! 676: } ! 677: else ! 678: self->monsterinfo.currentmove = &tank_move_attack_blast; ! 679: } ! 680: } ! 681: ! 682: ! 683: // ! 684: // death ! 685: // ! 686: ! 687: void tank_dead (edict_t *self) ! 688: { ! 689: VectorSet (self->mins, -16, -16, -16); ! 690: VectorSet (self->maxs, 16, 16, -0); ! 691: self->movetype = MOVETYPE_TOSS; ! 692: self->svflags |= SVF_DEADMONSTER; ! 693: self->nextthink = 0; ! 694: gi.linkentity (self); ! 695: } ! 696: ! 697: mframe_t tank_frames_death1 [] = ! 698: { ! 699: ai_move, -7, NULL, ! 700: ai_move, -2, NULL, ! 701: ai_move, -2, NULL, ! 702: ai_move, 1, NULL, ! 703: ai_move, 3, NULL, ! 704: ai_move, 6, NULL, ! 705: ai_move, 1, NULL, ! 706: ai_move, 1, NULL, ! 707: ai_move, 2, NULL, ! 708: ai_move, 0, NULL, ! 709: ai_move, 0, NULL, ! 710: ai_move, 0, NULL, ! 711: ai_move, -2, NULL, ! 712: ai_move, 0, NULL, ! 713: ai_move, 0, NULL, ! 714: ai_move, -3, NULL, ! 715: ai_move, 0, NULL, ! 716: ai_move, 0, NULL, ! 717: ai_move, 0, NULL, ! 718: ai_move, 0, NULL, ! 719: ai_move, 0, NULL, ! 720: ai_move, 0, NULL, ! 721: ai_move, -4, NULL, ! 722: ai_move, -6, NULL, ! 723: ai_move, -4, NULL, ! 724: ai_move, -5, NULL, ! 725: ai_move, -7, NULL, ! 726: ai_move, -15, tank_thud, ! 727: ai_move, -5, NULL, ! 728: ai_move, 0, NULL, ! 729: ai_move, 0, NULL, ! 730: ai_move, 0, NULL ! 731: }; ! 732: mmove_t tank_move_death = {FRAME_death101, FRAME_death132, tank_frames_death1, tank_dead}; ! 733: ! 734: void tank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 735: { ! 736: int n; ! 737: ! 738: // check for gib ! 739: if (self->health <= self->gib_health) ! 740: { ! 741: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); ! 742: for (n= 0; n < 1 /*4*/; n++) ! 743: ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); ! 744: for (n= 0; n < 4; n++) ! 745: ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC); ! 746: ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC); ! 747: ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC); ! 748: self->deadflag = DEAD_DEAD; ! 749: return; ! 750: } ! 751: ! 752: if (self->deadflag == DEAD_DEAD) ! 753: return; ! 754: ! 755: // regular death ! 756: gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); ! 757: self->deadflag = DEAD_DEAD; ! 758: self->takedamage = DAMAGE_YES; ! 759: ! 760: self->monsterinfo.currentmove = &tank_move_death; ! 761: ! 762: } ! 763: ! 764: ! 765: // ! 766: // monster_tank ! 767: // ! 768: ! 769: /*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight ! 770: */ ! 771: /*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight ! 772: */ ! 773: void SP_monster_tank (edict_t *self) ! 774: { ! 775: if (deathmatch->value) ! 776: { ! 777: G_FreeEdict (self); ! 778: return; ! 779: } ! 780: ! 781: self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2"); ! 782: VectorSet (self->mins, -32, -32, -16); ! 783: VectorSet (self->maxs, 32, 32, 72); ! 784: self->movetype = MOVETYPE_STEP; ! 785: self->solid = SOLID_BBOX; ! 786: ! 787: sound_pain = gi.soundindex ("tank/tnkpain2.wav"); ! 788: sound_thud = gi.soundindex ("tank/tnkdeth2.wav"); ! 789: sound_idle = gi.soundindex ("tank/tnkidle1.wav"); ! 790: sound_die = gi.soundindex ("tank/death.wav"); ! 791: sound_step = gi.soundindex ("tank/step.wav"); ! 792: sound_windup = gi.soundindex ("tank/tnkatck4.wav"); ! 793: sound_strike = gi.soundindex ("tank/tnkatck5.wav"); ! 794: sound_sight = gi.soundindex ("tank/sight1.wav"); ! 795: ! 796: gi.soundindex ("tank/tnkatck1.wav"); ! 797: gi.soundindex ("tank/tnkatk2a.wav"); ! 798: gi.soundindex ("tank/tnkatk2b.wav"); ! 799: gi.soundindex ("tank/tnkatk2c.wav"); ! 800: gi.soundindex ("tank/tnkatk2d.wav"); ! 801: gi.soundindex ("tank/tnkatk2e.wav"); ! 802: gi.soundindex ("tank/tnkatck3.wav"); ! 803: ! 804: if (strcmp(self->classname, "monster_tank_commander") == 0) ! 805: { ! 806: self->health = 1000; ! 807: self->gib_health = -225; ! 808: } ! 809: else ! 810: { ! 811: self->health = 750; ! 812: self->gib_health = -200; ! 813: } ! 814: ! 815: self->mass = 500; ! 816: ! 817: self->pain = tank_pain; ! 818: self->die = tank_die; ! 819: self->monsterinfo.stand = tank_stand; ! 820: self->monsterinfo.walk = tank_walk; ! 821: self->monsterinfo.run = tank_run; ! 822: self->monsterinfo.dodge = NULL; ! 823: self->monsterinfo.attack = tank_attack; ! 824: self->monsterinfo.melee = NULL; ! 825: self->monsterinfo.sight = tank_sight; ! 826: self->monsterinfo.idle = tank_idle; ! 827: ! 828: gi.linkentity (self); ! 829: ! 830: self->monsterinfo.currentmove = &tank_move_stand; ! 831: self->monsterinfo.scale = MODEL_SCALE; ! 832: ! 833: walkmonster_start(self); ! 834: ! 835: if (strcmp(self->classname, "monster_tank_commander") == 0) ! 836: self->s.skinnum = 2; ! 837: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.