|
|
1.1 root 1: /* 1.1.1.2 ! root 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: /* 1.1 root 21: ============================================================================== 22: 23: MEDIC 24: 25: ============================================================================== 26: */ 27: 28: #include "g_local.h" 29: #include "m_medic.h" 30: 31: qboolean visible (edict_t *self, edict_t *other); 32: 33: 34: static int sound_idle1; 35: static int sound_pain1; 36: static int sound_pain2; 37: static int sound_die; 38: static int sound_sight; 39: static int sound_search; 40: static int sound_hook_launch; 41: static int sound_hook_hit; 42: static int sound_hook_heal; 43: static int sound_hook_retract; 44: 45: 46: edict_t *medic_FindDeadMonster (edict_t *self) 47: { 48: edict_t *ent = NULL; 49: edict_t *best = NULL; 50: 51: while ((ent = findradius(ent, self->s.origin, 1024)) != NULL) 52: { 53: if (ent == self) 54: continue; 55: if (!(ent->svflags & SVF_MONSTER)) 56: continue; 57: if (ent->monsterinfo.aiflags & AI_GOOD_GUY) 58: continue; 59: if (ent->owner) 60: continue; 61: if (ent->health > 0) 62: continue; 63: if (ent->nextthink) 64: continue; 65: if (!visible(self, ent)) 66: continue; 67: if (!best) 68: { 69: best = ent; 70: continue; 71: } 72: if (ent->max_health <= best->max_health) 73: continue; 74: best = ent; 75: } 76: 77: return best; 78: } 79: 80: void medic_idle (edict_t *self) 81: { 82: edict_t *ent; 83: 84: gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0); 85: 86: ent = medic_FindDeadMonster(self); 87: if (ent) 88: { 89: self->enemy = ent; 90: self->enemy->owner = self; 91: self->monsterinfo.aiflags |= AI_MEDIC; 92: FoundTarget (self); 93: } 94: } 95: 96: void medic_search (edict_t *self) 97: { 98: edict_t *ent; 99: 100: gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0); 101: 102: if (!self->oldenemy) 103: { 104: ent = medic_FindDeadMonster(self); 105: if (ent) 106: { 107: self->oldenemy = self->enemy; 108: self->enemy = ent; 109: self->enemy->owner = self; 110: self->monsterinfo.aiflags |= AI_MEDIC; 111: FoundTarget (self); 112: } 113: } 114: } 115: 116: void medic_sight (edict_t *self, edict_t *other) 117: { 118: gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); 119: } 120: 121: 122: mframe_t medic_frames_stand [] = 123: { 124: ai_stand, 0, medic_idle, 125: ai_stand, 0, NULL, 126: ai_stand, 0, NULL, 127: ai_stand, 0, NULL, 128: ai_stand, 0, NULL, 129: ai_stand, 0, NULL, 130: ai_stand, 0, NULL, 131: ai_stand, 0, NULL, 132: ai_stand, 0, NULL, 133: ai_stand, 0, NULL, 134: ai_stand, 0, NULL, 135: ai_stand, 0, NULL, 136: ai_stand, 0, NULL, 137: ai_stand, 0, NULL, 138: ai_stand, 0, NULL, 139: ai_stand, 0, NULL, 140: ai_stand, 0, NULL, 141: ai_stand, 0, NULL, 142: ai_stand, 0, NULL, 143: ai_stand, 0, NULL, 144: ai_stand, 0, NULL, 145: ai_stand, 0, NULL, 146: ai_stand, 0, NULL, 147: ai_stand, 0, NULL, 148: ai_stand, 0, NULL, 149: ai_stand, 0, NULL, 150: ai_stand, 0, NULL, 151: ai_stand, 0, NULL, 152: ai_stand, 0, NULL, 153: ai_stand, 0, NULL, 154: ai_stand, 0, NULL, 155: ai_stand, 0, NULL, 156: ai_stand, 0, NULL, 157: ai_stand, 0, NULL, 158: ai_stand, 0, NULL, 159: ai_stand, 0, NULL, 160: ai_stand, 0, NULL, 161: ai_stand, 0, NULL, 162: ai_stand, 0, NULL, 163: ai_stand, 0, NULL, 164: ai_stand, 0, NULL, 165: ai_stand, 0, NULL, 166: ai_stand, 0, NULL, 167: ai_stand, 0, NULL, 168: ai_stand, 0, NULL, 169: ai_stand, 0, NULL, 170: ai_stand, 0, NULL, 171: ai_stand, 0, NULL, 172: ai_stand, 0, NULL, 173: ai_stand, 0, NULL, 174: ai_stand, 0, NULL, 175: ai_stand, 0, NULL, 176: ai_stand, 0, NULL, 177: ai_stand, 0, NULL, 178: ai_stand, 0, NULL, 179: ai_stand, 0, NULL, 180: ai_stand, 0, NULL, 181: ai_stand, 0, NULL, 182: ai_stand, 0, NULL, 183: ai_stand, 0, NULL, 184: ai_stand, 0, NULL, 185: ai_stand, 0, NULL, 186: ai_stand, 0, NULL, 187: ai_stand, 0, NULL, 188: ai_stand, 0, NULL, 189: ai_stand, 0, NULL, 190: ai_stand, 0, NULL, 191: ai_stand, 0, NULL, 192: ai_stand, 0, NULL, 193: ai_stand, 0, NULL, 194: ai_stand, 0, NULL, 195: ai_stand, 0, NULL, 196: ai_stand, 0, NULL, 197: ai_stand, 0, NULL, 198: ai_stand, 0, NULL, 199: ai_stand, 0, NULL, 200: ai_stand, 0, NULL, 201: ai_stand, 0, NULL, 202: ai_stand, 0, NULL, 203: ai_stand, 0, NULL, 204: ai_stand, 0, NULL, 205: ai_stand, 0, NULL, 206: ai_stand, 0, NULL, 207: ai_stand, 0, NULL, 208: ai_stand, 0, NULL, 209: ai_stand, 0, NULL, 210: ai_stand, 0, NULL, 211: ai_stand, 0, NULL, 212: ai_stand, 0, NULL, 213: ai_stand, 0, NULL, 214: 215: }; 216: mmove_t medic_move_stand = {FRAME_wait1, FRAME_wait90, medic_frames_stand, NULL}; 217: 218: void medic_stand (edict_t *self) 219: { 220: self->monsterinfo.currentmove = &medic_move_stand; 221: } 222: 223: 224: mframe_t medic_frames_walk [] = 225: { 226: ai_walk, 6.2, NULL, 227: ai_walk, 18.1, NULL, 228: ai_walk, 1, NULL, 229: ai_walk, 9, NULL, 230: ai_walk, 10, NULL, 231: ai_walk, 9, NULL, 232: ai_walk, 11, NULL, 233: ai_walk, 11.6, NULL, 234: ai_walk, 2, NULL, 235: ai_walk, 9.9, NULL, 236: ai_walk, 14, NULL, 237: ai_walk, 9.3, NULL 238: }; 239: mmove_t medic_move_walk = {FRAME_walk1, FRAME_walk12, medic_frames_walk, NULL}; 240: 241: void medic_walk (edict_t *self) 242: { 243: self->monsterinfo.currentmove = &medic_move_walk; 244: } 245: 246: 247: mframe_t medic_frames_run [] = 248: { 249: ai_run, 18, NULL, 250: ai_run, 22.5, NULL, 251: ai_run, 25.4, NULL, 252: ai_run, 23.4, NULL, 253: ai_run, 24, NULL, 254: ai_run, 35.6, NULL 255: 256: }; 257: mmove_t medic_move_run = {FRAME_run1, FRAME_run6, medic_frames_run, NULL}; 258: 259: void medic_run (edict_t *self) 260: { 261: if (!(self->monsterinfo.aiflags & AI_MEDIC)) 262: { 263: edict_t *ent; 264: 265: ent = medic_FindDeadMonster(self); 266: if (ent) 267: { 268: self->oldenemy = self->enemy; 269: self->enemy = ent; 270: self->enemy->owner = self; 271: self->monsterinfo.aiflags |= AI_MEDIC; 272: FoundTarget (self); 273: return; 274: } 275: } 276: 277: if (self->monsterinfo.aiflags & AI_STAND_GROUND) 278: self->monsterinfo.currentmove = &medic_move_stand; 279: else 280: self->monsterinfo.currentmove = &medic_move_run; 281: } 282: 283: 284: mframe_t medic_frames_pain1 [] = 285: { 286: ai_move, 0, NULL, 287: ai_move, 0, NULL, 288: ai_move, 0, NULL, 289: ai_move, 0, NULL, 290: ai_move, 0, NULL, 291: ai_move, 0, NULL, 292: ai_move, 0, NULL, 293: ai_move, 0, NULL 294: }; 295: mmove_t medic_move_pain1 = {FRAME_paina1, FRAME_paina8, medic_frames_pain1, medic_run}; 296: 297: mframe_t medic_frames_pain2 [] = 298: { 299: ai_move, 0, NULL, 300: ai_move, 0, NULL, 301: ai_move, 0, NULL, 302: ai_move, 0, NULL, 303: ai_move, 0, NULL, 304: ai_move, 0, NULL, 305: ai_move, 0, NULL, 306: ai_move, 0, NULL, 307: ai_move, 0, NULL, 308: ai_move, 0, NULL, 309: ai_move, 0, NULL, 310: ai_move, 0, NULL, 311: ai_move, 0, NULL, 312: ai_move, 0, NULL, 313: ai_move, 0, NULL 314: }; 315: mmove_t medic_move_pain2 = {FRAME_painb1, FRAME_painb15, medic_frames_pain2, medic_run}; 316: 317: void medic_pain (edict_t *self, edict_t *other, float kick, int damage) 318: { 319: if (self->health < (self->max_health / 2)) 320: self->s.skinnum = 1; 321: 322: if (level.time < self->pain_debounce_time) 323: return; 324: 325: self->pain_debounce_time = level.time + 3; 326: 327: if (skill->value == 3) 328: return; // no pain anims in nightmare 329: 330: if (random() < 0.5) 331: { 332: self->monsterinfo.currentmove = &medic_move_pain1; 333: gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0); 334: } 335: else 336: { 337: self->monsterinfo.currentmove = &medic_move_pain2; 338: gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0); 339: } 340: } 341: 342: void medic_fire_blaster (edict_t *self) 343: { 344: vec3_t start; 345: vec3_t forward, right; 346: vec3_t end; 347: vec3_t dir; 348: int effect; 349: 350: if ((self->s.frame == FRAME_attack9) || (self->s.frame == FRAME_attack12)) 351: effect = EF_BLASTER; 352: else if ((self->s.frame == FRAME_attack19) || (self->s.frame == FRAME_attack22) || (self->s.frame == FRAME_attack25) || (self->s.frame == FRAME_attack28)) 353: effect = EF_HYPERBLASTER; 354: else 355: effect = 0; 356: 357: AngleVectors (self->s.angles, forward, right, NULL); 358: G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MEDIC_BLASTER_1], forward, right, start); 359: 360: VectorCopy (self->enemy->s.origin, end); 361: end[2] += self->enemy->viewheight; 362: VectorSubtract (end, start, dir); 363: 364: monster_fire_blaster (self, start, dir, 2, 1000, MZ2_MEDIC_BLASTER_1, effect); 365: } 366: 367: 368: void medic_dead (edict_t *self) 369: { 370: VectorSet (self->mins, -16, -16, -24); 371: VectorSet (self->maxs, 16, 16, -8); 372: self->movetype = MOVETYPE_TOSS; 373: self->svflags |= SVF_DEADMONSTER; 374: self->nextthink = 0; 375: gi.linkentity (self); 376: } 377: 378: mframe_t medic_frames_death [] = 379: { 380: ai_move, 0, NULL, 381: ai_move, 0, NULL, 382: ai_move, 0, NULL, 383: ai_move, 0, NULL, 384: ai_move, 0, NULL, 385: ai_move, 0, NULL, 386: ai_move, 0, NULL, 387: ai_move, 0, NULL, 388: ai_move, 0, NULL, 389: ai_move, 0, NULL, 390: ai_move, 0, NULL, 391: ai_move, 0, NULL, 392: ai_move, 0, NULL, 393: ai_move, 0, NULL, 394: ai_move, 0, NULL, 395: ai_move, 0, NULL, 396: ai_move, 0, NULL, 397: ai_move, 0, NULL, 398: ai_move, 0, NULL, 399: ai_move, 0, NULL, 400: ai_move, 0, NULL, 401: ai_move, 0, NULL, 402: ai_move, 0, NULL, 403: ai_move, 0, NULL, 404: ai_move, 0, NULL, 405: ai_move, 0, NULL, 406: ai_move, 0, NULL, 407: ai_move, 0, NULL, 408: ai_move, 0, NULL, 409: ai_move, 0, NULL 410: }; 411: mmove_t medic_move_death = {FRAME_death1, FRAME_death30, medic_frames_death, medic_dead}; 412: 413: void medic_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 414: { 415: int n; 416: 417: // if we had a pending patient, free him up for another medic 418: if ((self->enemy) && (self->enemy->owner == self)) 419: self->enemy->owner = NULL; 420: 421: // check for gib 422: if (self->health <= self->gib_health) 423: { 424: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 425: for (n= 0; n < 2; n++) 426: ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); 427: for (n= 0; n < 4; n++) 428: ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 429: ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 430: self->deadflag = DEAD_DEAD; 431: return; 432: } 433: 434: if (self->deadflag == DEAD_DEAD) 435: return; 436: 437: // regular death 438: gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); 439: self->deadflag = DEAD_DEAD; 440: self->takedamage = DAMAGE_YES; 441: 442: self->monsterinfo.currentmove = &medic_move_death; 443: } 444: 445: 446: void medic_duck_down (edict_t *self) 447: { 448: if (self->monsterinfo.aiflags & AI_DUCKED) 449: return; 450: self->monsterinfo.aiflags |= AI_DUCKED; 451: self->maxs[2] -= 32; 452: self->takedamage = DAMAGE_YES; 453: self->monsterinfo.pausetime = level.time + 1; 454: gi.linkentity (self); 455: } 456: 457: void medic_duck_hold (edict_t *self) 458: { 459: if (level.time >= self->monsterinfo.pausetime) 460: self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; 461: else 462: self->monsterinfo.aiflags |= AI_HOLD_FRAME; 463: } 464: 465: void medic_duck_up (edict_t *self) 466: { 467: self->monsterinfo.aiflags &= ~AI_DUCKED; 468: self->maxs[2] += 32; 469: self->takedamage = DAMAGE_AIM; 470: gi.linkentity (self); 471: } 472: 473: mframe_t medic_frames_duck [] = 474: { 475: ai_move, -1, NULL, 476: ai_move, -1, NULL, 477: ai_move, -1, medic_duck_down, 478: ai_move, -1, medic_duck_hold, 479: ai_move, -1, NULL, 480: ai_move, -1, NULL, 481: ai_move, -1, medic_duck_up, 482: ai_move, -1, NULL, 483: ai_move, -1, NULL, 484: ai_move, -1, NULL, 485: ai_move, -1, NULL, 486: ai_move, -1, NULL, 487: ai_move, -1, NULL, 488: ai_move, -1, NULL, 489: ai_move, -1, NULL, 490: ai_move, -1, NULL 491: }; 492: mmove_t medic_move_duck = {FRAME_duck1, FRAME_duck16, medic_frames_duck, medic_run}; 493: 494: void medic_dodge (edict_t *self, edict_t *attacker, float eta) 495: { 496: if (random() > 0.25) 497: return; 498: 499: if (!self->enemy) 500: self->enemy = attacker; 501: 502: self->monsterinfo.currentmove = &medic_move_duck; 503: } 504: 505: mframe_t medic_frames_attackHyperBlaster [] = 506: { 507: ai_charge, 0, NULL, 508: ai_charge, 0, NULL, 509: ai_charge, 0, NULL, 510: ai_charge, 0, NULL, 511: ai_charge, 0, medic_fire_blaster, 512: ai_charge, 0, medic_fire_blaster, 513: ai_charge, 0, medic_fire_blaster, 514: ai_charge, 0, medic_fire_blaster, 515: ai_charge, 0, medic_fire_blaster, 516: ai_charge, 0, medic_fire_blaster, 517: ai_charge, 0, medic_fire_blaster, 518: ai_charge, 0, medic_fire_blaster, 519: ai_charge, 0, medic_fire_blaster, 520: ai_charge, 0, medic_fire_blaster, 521: ai_charge, 0, medic_fire_blaster, 522: ai_charge, 0, medic_fire_blaster 523: }; 524: mmove_t medic_move_attackHyperBlaster = {FRAME_attack15, FRAME_attack30, medic_frames_attackHyperBlaster, medic_run}; 525: 526: 527: void medic_continue (edict_t *self) 528: { 529: if (visible (self, self->enemy) ) 530: if (random() <= 0.95) 531: self->monsterinfo.currentmove = &medic_move_attackHyperBlaster; 532: } 533: 534: 535: mframe_t medic_frames_attackBlaster [] = 536: { 537: ai_charge, 0, NULL, 538: ai_charge, 5, NULL, 539: ai_charge, 5, NULL, 540: ai_charge, 3, NULL, 541: ai_charge, 2, NULL, 542: ai_charge, 0, NULL, 543: ai_charge, 0, NULL, 544: ai_charge, 0, NULL, 545: ai_charge, 0, medic_fire_blaster, 546: ai_charge, 0, NULL, 547: ai_charge, 0, NULL, 548: ai_charge, 0, medic_fire_blaster, 549: ai_charge, 0, NULL, 550: ai_charge, 0, medic_continue // Change to medic_continue... Else, go to frame 32 551: }; 552: mmove_t medic_move_attackBlaster = {FRAME_attack1, FRAME_attack14, medic_frames_attackBlaster, medic_run}; 553: 554: 555: void medic_hook_launch (edict_t *self) 556: { 557: gi.sound (self, CHAN_WEAPON, sound_hook_launch, 1, ATTN_NORM, 0); 558: } 559: 560: void ED_CallSpawn (edict_t *ent); 561: 562: static vec3_t medic_cable_offsets[] = 563: { 564: 45.0, -9.2, 15.5, 565: 48.4, -9.7, 15.2, 566: 47.8, -9.8, 15.8, 567: 47.3, -9.3, 14.3, 568: 45.4, -10.1, 13.1, 569: 41.9, -12.7, 12.0, 570: 37.8, -15.8, 11.2, 571: 34.3, -18.4, 10.7, 572: 32.7, -19.7, 10.4, 573: 32.7, -19.7, 10.4 574: }; 575: 576: void medic_cable_attack (edict_t *self) 577: { 578: vec3_t offset, start, end, f, r; 579: trace_t tr; 580: vec3_t dir, angles; 581: float distance; 582: 583: if (!self->enemy->inuse) 584: return; 585: 586: AngleVectors (self->s.angles, f, r, NULL); 587: VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset); 588: G_ProjectSource (self->s.origin, offset, f, r, start); 589: 590: // check for max distance 591: VectorSubtract (start, self->enemy->s.origin, dir); 592: distance = VectorLength(dir); 593: if (distance > 256) 594: return; 595: 596: // check for min/max pitch 597: vectoangles (dir, angles); 598: if (angles[0] < -180) 599: angles[0] += 360; 600: if (fabs(angles[0]) > 45) 601: return; 602: 603: tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT); 604: if (tr.fraction != 1.0 && tr.ent != self->enemy) 605: return; 606: 607: if (self->s.frame == FRAME_attack43) 608: { 609: gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0); 610: self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; 611: } 612: else if (self->s.frame == FRAME_attack50) 613: { 614: self->enemy->spawnflags = 0; 615: self->enemy->monsterinfo.aiflags = 0; 616: self->enemy->target = NULL; 617: self->enemy->targetname = NULL; 618: self->enemy->combattarget = NULL; 619: self->enemy->deathtarget = NULL; 620: self->enemy->owner = self; 621: ED_CallSpawn (self->enemy); 622: self->enemy->owner = NULL; 623: if (self->enemy->think) 624: { 625: self->enemy->nextthink = level.time; 626: self->enemy->think (self->enemy); 627: } 628: self->enemy->monsterinfo.aiflags |= AI_RESURRECTING; 629: if (self->oldenemy && self->oldenemy->client) 630: { 631: self->enemy->enemy = self->oldenemy; 632: FoundTarget (self->enemy); 633: } 634: } 635: else 636: { 637: if (self->s.frame == FRAME_attack44) 638: gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0); 639: } 640: 641: // adjust start for beam origin being in middle of a segment 642: VectorMA (start, 8, f, start); 643: 644: // adjust end z for end spot since the monster is currently dead 645: VectorCopy (self->enemy->s.origin, end); 646: end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2; 647: 648: gi.WriteByte (svc_temp_entity); 649: gi.WriteByte (TE_MEDIC_CABLE_ATTACK); 650: gi.WriteShort (self - g_edicts); 651: gi.WritePosition (start); 652: gi.WritePosition (end); 653: gi.multicast (self->s.origin, MULTICAST_PVS); 654: } 655: 656: void medic_hook_retract (edict_t *self) 657: { 658: gi.sound (self, CHAN_WEAPON, sound_hook_retract, 1, ATTN_NORM, 0); 659: self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING; 660: } 661: 662: mframe_t medic_frames_attackCable [] = 663: { 664: ai_move, 2, NULL, 665: ai_move, 3, NULL, 666: ai_move, 5, NULL, 667: ai_move, 4.4, NULL, 668: ai_charge, 4.7, NULL, 669: ai_charge, 5, NULL, 670: ai_charge, 6, NULL, 671: ai_charge, 4, NULL, 672: ai_charge, 0, NULL, 673: ai_move, 0, medic_hook_launch, 674: ai_move, 0, medic_cable_attack, 675: ai_move, 0, medic_cable_attack, 676: ai_move, 0, medic_cable_attack, 677: ai_move, 0, medic_cable_attack, 678: ai_move, 0, medic_cable_attack, 679: ai_move, 0, medic_cable_attack, 680: ai_move, 0, medic_cable_attack, 681: ai_move, 0, medic_cable_attack, 682: ai_move, 0, medic_cable_attack, 683: ai_move, -15, medic_hook_retract, 684: ai_move, -1.5, NULL, 685: ai_move, -1.2, NULL, 686: ai_move, -3, NULL, 687: ai_move, -2, NULL, 688: ai_move, 0.3, NULL, 689: ai_move, 0.7, NULL, 690: ai_move, 1.2, NULL, 691: ai_move, 1.3, NULL 692: }; 693: mmove_t medic_move_attackCable = {FRAME_attack33, FRAME_attack60, medic_frames_attackCable, medic_run}; 694: 695: 696: void medic_attack(edict_t *self) 697: { 698: if (self->monsterinfo.aiflags & AI_MEDIC) 699: self->monsterinfo.currentmove = &medic_move_attackCable; 700: else 701: self->monsterinfo.currentmove = &medic_move_attackBlaster; 702: } 703: 704: qboolean medic_checkattack (edict_t *self) 705: { 706: if (self->monsterinfo.aiflags & AI_MEDIC) 707: { 708: medic_attack(self); 709: return true; 710: } 711: 712: return M_CheckAttack (self); 713: } 714: 715: 716: /*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 717: */ 718: void SP_monster_medic (edict_t *self) 719: { 720: if (deathmatch->value) 721: { 722: G_FreeEdict (self); 723: return; 724: } 725: 726: sound_idle1 = gi.soundindex ("medic/idle.wav"); 727: sound_pain1 = gi.soundindex ("medic/medpain1.wav"); 728: sound_pain2 = gi.soundindex ("medic/medpain2.wav"); 729: sound_die = gi.soundindex ("medic/meddeth1.wav"); 730: sound_sight = gi.soundindex ("medic/medsght1.wav"); 731: sound_search = gi.soundindex ("medic/medsrch1.wav"); 732: sound_hook_launch = gi.soundindex ("medic/medatck2.wav"); 733: sound_hook_hit = gi.soundindex ("medic/medatck3.wav"); 734: sound_hook_heal = gi.soundindex ("medic/medatck4.wav"); 735: sound_hook_retract = gi.soundindex ("medic/medatck5.wav"); 736: 737: gi.soundindex ("medic/medatck1.wav"); 738: 739: self->movetype = MOVETYPE_STEP; 740: self->solid = SOLID_BBOX; 741: self->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2"); 742: VectorSet (self->mins, -24, -24, -24); 743: VectorSet (self->maxs, 24, 24, 32); 744: 745: self->health = 300; 746: self->gib_health = -130; 747: self->mass = 400; 748: 749: self->pain = medic_pain; 750: self->die = medic_die; 751: 752: self->monsterinfo.stand = medic_stand; 753: self->monsterinfo.walk = medic_walk; 754: self->monsterinfo.run = medic_run; 755: self->monsterinfo.dodge = medic_dodge; 756: self->monsterinfo.attack = medic_attack; 757: self->monsterinfo.melee = NULL; 758: self->monsterinfo.sight = medic_sight; 759: self->monsterinfo.idle = medic_idle; 760: self->monsterinfo.search = medic_search; 761: self->monsterinfo.checkattack = medic_checkattack; 762: 763: gi.linkentity (self); 764: 765: self->monsterinfo.currentmove = &medic_move_stand; 766: self->monsterinfo.scale = MODEL_SCALE; 767: 768: walkmonster_start (self); 769: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.