|
|
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: mutant 24: 25: ============================================================================== 26: */ 27: 28: #include "g_local.h" 29: #include "m_mutant.h" 30: 31: 32: static int sound_swing; 33: static int sound_hit; 34: static int sound_hit2; 35: static int sound_death; 36: static int sound_idle; 37: static int sound_pain1; 38: static int sound_pain2; 39: static int sound_sight; 40: static int sound_search; 41: static int sound_step1; 42: static int sound_step2; 43: static int sound_step3; 44: static int sound_thud; 45: 46: // 47: // SOUNDS 48: // 49: 50: void mutant_step (edict_t *self) 51: { 52: int n; 53: n = (rand() + 1) % 3; 54: if (n == 0) 55: gi.sound (self, CHAN_VOICE, sound_step1, 1, ATTN_NORM, 0); 56: else if (n == 1) 57: gi.sound (self, CHAN_VOICE, sound_step2, 1, ATTN_NORM, 0); 58: else 59: gi.sound (self, CHAN_VOICE, sound_step3, 1, ATTN_NORM, 0); 60: } 61: 62: void mutant_sight (edict_t *self, edict_t *other) 63: { 64: gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); 65: } 66: 67: void mutant_search (edict_t *self) 68: { 69: gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0); 70: } 71: 72: void mutant_swing (edict_t *self) 73: { 74: gi.sound (self, CHAN_VOICE, sound_swing, 1, ATTN_NORM, 0); 75: } 76: 77: 78: // 79: // STAND 80: // 81: 82: mframe_t mutant_frames_stand [] = 83: { 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, // 10 94: 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, // 20 105: 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: ai_stand, 0, NULL, 113: ai_stand, 0, NULL, 114: ai_stand, 0, NULL, 115: ai_stand, 0, NULL, // 30 116: 117: ai_stand, 0, NULL, 118: ai_stand, 0, NULL, 119: ai_stand, 0, NULL, 120: ai_stand, 0, NULL, 121: ai_stand, 0, NULL, 122: ai_stand, 0, NULL, 123: ai_stand, 0, NULL, 124: ai_stand, 0, NULL, 125: ai_stand, 0, NULL, 126: ai_stand, 0, NULL, // 40 127: 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, // 50 138: 139: ai_stand, 0, NULL 140: }; 141: mmove_t mutant_move_stand = {FRAME_stand101, FRAME_stand151, mutant_frames_stand, NULL}; 142: 143: void mutant_stand (edict_t *self) 144: { 145: self->monsterinfo.currentmove = &mutant_move_stand; 146: } 147: 148: 149: // 150: // IDLE 151: // 152: 153: void mutant_idle_loop (edict_t *self) 154: { 155: if (random() < 0.75) 156: self->monsterinfo.nextframe = FRAME_stand155; 157: } 158: 159: mframe_t mutant_frames_idle [] = 160: { 161: ai_stand, 0, NULL, 162: ai_stand, 0, NULL, 163: ai_stand, 0, NULL, 164: ai_stand, 0, NULL, // scratch loop start 165: ai_stand, 0, NULL, 166: ai_stand, 0, NULL, 167: ai_stand, 0, mutant_idle_loop, // scratch loop end 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: }; 175: mmove_t mutant_move_idle = {FRAME_stand152, FRAME_stand164, mutant_frames_idle, mutant_stand}; 176: 177: void mutant_idle (edict_t *self) 178: { 179: self->monsterinfo.currentmove = &mutant_move_idle; 180: gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0); 181: } 182: 183: 184: // 185: // WALK 186: // 187: 188: void mutant_walk (edict_t *self); 189: 190: mframe_t mutant_frames_walk [] = 191: { 192: ai_walk, 3, NULL, 193: ai_walk, 1, NULL, 194: ai_walk, 5, NULL, 195: ai_walk, 10, NULL, 196: ai_walk, 13, NULL, 197: ai_walk, 10, NULL, 198: ai_walk, 0, NULL, 199: ai_walk, 5, NULL, 200: ai_walk, 6, NULL, 201: ai_walk, 16, NULL, 202: ai_walk, 15, NULL, 203: ai_walk, 6, NULL 204: }; 205: mmove_t mutant_move_walk = {FRAME_walk05, FRAME_walk16, mutant_frames_walk, NULL}; 206: 207: void mutant_walk_loop (edict_t *self) 208: { 209: self->monsterinfo.currentmove = &mutant_move_walk; 210: } 211: 212: mframe_t mutant_frames_start_walk [] = 213: { 214: ai_walk, 5, NULL, 215: ai_walk, 5, NULL, 216: ai_walk, -2, NULL, 217: ai_walk, 1, NULL 218: }; 219: mmove_t mutant_move_start_walk = {FRAME_walk01, FRAME_walk04, mutant_frames_start_walk, mutant_walk_loop}; 220: 221: void mutant_walk (edict_t *self) 222: { 223: self->monsterinfo.currentmove = &mutant_move_start_walk; 224: } 225: 226: 227: // 228: // RUN 229: // 230: 231: mframe_t mutant_frames_run [] = 232: { 233: ai_run, 40, NULL, 234: ai_run, 40, mutant_step, 235: ai_run, 24, NULL, 236: ai_run, 5, mutant_step, 237: ai_run, 17, NULL, 238: ai_run, 10, NULL 239: }; 240: mmove_t mutant_move_run = {FRAME_run03, FRAME_run08, mutant_frames_run, NULL}; 241: 242: void mutant_run (edict_t *self) 243: { 244: if (self->monsterinfo.aiflags & AI_STAND_GROUND) 245: self->monsterinfo.currentmove = &mutant_move_stand; 246: else 247: self->monsterinfo.currentmove = &mutant_move_run; 248: } 249: 250: 251: // 252: // MELEE 253: // 254: 255: void mutant_hit_left (edict_t *self) 256: { 257: vec3_t aim; 258: 259: VectorSet (aim, MELEE_DISTANCE, self->mins[0], 8); 260: if (fire_hit (self, aim, (10 + (rand() %5)), 100)) 261: gi.sound (self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0); 262: else 263: gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0); 264: } 265: 266: void mutant_hit_right (edict_t *self) 267: { 268: vec3_t aim; 269: 270: VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 8); 271: if (fire_hit (self, aim, (10 + (rand() %5)), 100)) 272: gi.sound (self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0); 273: else 274: gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0); 275: } 276: 277: void mutant_check_refire (edict_t *self) 278: { 279: if (!self->enemy || !self->enemy->inuse || self->enemy->health <= 0) 280: return; 281: 282: if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) 283: self->monsterinfo.nextframe = FRAME_attack09; 284: } 285: 286: mframe_t mutant_frames_attack [] = 287: { 288: ai_charge, 0, NULL, 289: ai_charge, 0, NULL, 290: ai_charge, 0, mutant_hit_left, 291: ai_charge, 0, NULL, 292: ai_charge, 0, NULL, 293: ai_charge, 0, mutant_hit_right, 294: ai_charge, 0, mutant_check_refire 295: }; 296: mmove_t mutant_move_attack = {FRAME_attack09, FRAME_attack15, mutant_frames_attack, mutant_run}; 297: 298: void mutant_melee (edict_t *self) 299: { 300: self->monsterinfo.currentmove = &mutant_move_attack; 301: } 302: 303: 304: // 305: // ATTACK 306: // 307: 308: void mutant_jump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) 309: { 310: if (self->health <= 0) 311: { 312: self->touch = NULL; 313: return; 314: } 315: 316: if (other->takedamage) 317: { 318: if (VectorLength(self->velocity) > 400) 319: { 320: vec3_t point; 321: vec3_t normal; 322: int damage; 323: 324: VectorCopy (self->velocity, normal); 325: VectorNormalize(normal); 326: VectorMA (self->s.origin, self->maxs[0], normal, point); 327: damage = 40 + 10 * random(); 328: T_Damage (other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_UNKNOWN); 329: } 330: } 331: 332: if (!M_CheckBottom (self)) 333: { 334: if (self->groundentity) 335: { 336: self->monsterinfo.nextframe = FRAME_attack02; 337: self->touch = NULL; 338: } 339: return; 340: } 341: 342: self->touch = NULL; 343: } 344: 345: void mutant_jump_takeoff (edict_t *self) 346: { 347: vec3_t forward; 348: 349: gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); 350: AngleVectors (self->s.angles, forward, NULL, NULL); 351: self->s.origin[2] += 1; 352: VectorScale (forward, 600, self->velocity); 353: self->velocity[2] = 250; 354: self->groundentity = NULL; 355: self->monsterinfo.aiflags |= AI_DUCKED; 356: self->monsterinfo.attack_finished = level.time + 3; 357: self->touch = mutant_jump_touch; 358: } 359: 360: void mutant_check_landing (edict_t *self) 361: { 362: if (self->groundentity) 363: { 364: gi.sound (self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0); 365: self->monsterinfo.attack_finished = 0; 366: self->monsterinfo.aiflags &= ~AI_DUCKED; 367: return; 368: } 369: 370: if (level.time > self->monsterinfo.attack_finished) 371: self->monsterinfo.nextframe = FRAME_attack02; 372: else 373: self->monsterinfo.nextframe = FRAME_attack05; 374: } 375: 376: mframe_t mutant_frames_jump [] = 377: { 378: ai_charge, 0, NULL, 379: ai_charge, 17, NULL, 380: ai_charge, 15, mutant_jump_takeoff, 381: ai_charge, 15, NULL, 382: ai_charge, 15, mutant_check_landing, 383: ai_charge, 0, NULL, 384: ai_charge, 3, NULL, 385: ai_charge, 0, NULL 386: }; 387: mmove_t mutant_move_jump = {FRAME_attack01, FRAME_attack08, mutant_frames_jump, mutant_run}; 388: 389: void mutant_jump (edict_t *self) 390: { 391: self->monsterinfo.currentmove = &mutant_move_jump; 392: } 393: 394: 395: // 396: // CHECKATTACK 397: // 398: 399: qboolean mutant_check_melee (edict_t *self) 400: { 401: if (range (self, self->enemy) == RANGE_MELEE) 402: return true; 403: return false; 404: } 405: 406: qboolean mutant_check_jump (edict_t *self) 407: { 408: vec3_t v; 409: float distance; 410: 411: if (self->absmin[2] > (self->enemy->absmin[2] + 0.75 * self->enemy->size[2])) 412: return false; 413: 414: if (self->absmax[2] < (self->enemy->absmin[2] + 0.25 * self->enemy->size[2])) 415: return false; 416: 417: v[0] = self->s.origin[0] - self->enemy->s.origin[0]; 418: v[1] = self->s.origin[1] - self->enemy->s.origin[1]; 419: v[2] = 0; 420: distance = VectorLength(v); 421: 422: if (distance < 100) 423: return false; 424: if (distance > 100) 425: { 426: if (random() < 0.9) 427: return false; 428: } 429: 430: return true; 431: } 432: 433: qboolean mutant_checkattack (edict_t *self) 434: { 435: if (!self->enemy || self->enemy->health <= 0) 436: return false; 437: 438: if (mutant_check_melee(self)) 439: { 440: self->monsterinfo.attack_state = AS_MELEE; 441: return true; 442: } 443: 444: if (mutant_check_jump(self)) 445: { 446: self->monsterinfo.attack_state = AS_MISSILE; 447: // FIXME play a jump sound here 448: return true; 449: } 450: 451: return false; 452: } 453: 454: 455: // 456: // PAIN 457: // 458: 459: mframe_t mutant_frames_pain1 [] = 460: { 461: ai_move, 4, NULL, 462: ai_move, -3, NULL, 463: ai_move, -8, NULL, 464: ai_move, 2, NULL, 465: ai_move, 5, NULL 466: }; 467: mmove_t mutant_move_pain1 = {FRAME_pain101, FRAME_pain105, mutant_frames_pain1, mutant_run}; 468: 469: mframe_t mutant_frames_pain2 [] = 470: { 471: ai_move, -24,NULL, 472: ai_move, 11, NULL, 473: ai_move, 5, NULL, 474: ai_move, -2, NULL, 475: ai_move, 6, NULL, 476: ai_move, 4, NULL 477: }; 478: mmove_t mutant_move_pain2 = {FRAME_pain201, FRAME_pain206, mutant_frames_pain2, mutant_run}; 479: 480: mframe_t mutant_frames_pain3 [] = 481: { 482: ai_move, -22,NULL, 483: ai_move, 3, NULL, 484: ai_move, 3, NULL, 485: ai_move, 2, NULL, 486: ai_move, 1, NULL, 487: ai_move, 1, NULL, 488: ai_move, 6, NULL, 489: ai_move, 3, NULL, 490: ai_move, 2, NULL, 491: ai_move, 0, NULL, 492: ai_move, 1, NULL 493: }; 494: mmove_t mutant_move_pain3 = {FRAME_pain301, FRAME_pain311, mutant_frames_pain3, mutant_run}; 495: 496: void mutant_pain (edict_t *self, edict_t *other, float kick, int damage) 497: { 498: float r; 499: 500: if (self->health < (self->max_health / 2)) 501: self->s.skinnum = 1; 502: 503: if (level.time < self->pain_debounce_time) 504: return; 505: 506: self->pain_debounce_time = level.time + 3; 507: 508: if (skill->value == 3) 509: return; // no pain anims in nightmare 510: 511: r = random(); 512: if (r < 0.33) 513: { 514: gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0); 515: self->monsterinfo.currentmove = &mutant_move_pain1; 516: } 517: else if (r < 0.66) 518: { 519: gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0); 520: self->monsterinfo.currentmove = &mutant_move_pain2; 521: } 522: else 523: { 524: gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0); 525: self->monsterinfo.currentmove = &mutant_move_pain3; 526: } 527: } 528: 529: 530: // 531: // DEATH 532: // 533: 534: void mutant_dead (edict_t *self) 535: { 536: VectorSet (self->mins, -16, -16, -24); 537: VectorSet (self->maxs, 16, 16, -8); 538: self->movetype = MOVETYPE_TOSS; 539: self->svflags |= SVF_DEADMONSTER; 540: gi.linkentity (self); 541: 542: M_FlyCheck (self); 543: } 544: 545: mframe_t mutant_frames_death1 [] = 546: { 547: ai_move, 0, NULL, 548: ai_move, 0, NULL, 549: ai_move, 0, NULL, 550: ai_move, 0, NULL, 551: ai_move, 0, NULL, 552: ai_move, 0, NULL, 553: ai_move, 0, NULL, 554: ai_move, 0, NULL, 555: ai_move, 0, NULL 556: }; 557: mmove_t mutant_move_death1 = {FRAME_death101, FRAME_death109, mutant_frames_death1, mutant_dead}; 558: 559: mframe_t mutant_frames_death2 [] = 560: { 561: ai_move, 0, NULL, 562: ai_move, 0, NULL, 563: ai_move, 0, NULL, 564: ai_move, 0, NULL, 565: ai_move, 0, NULL, 566: ai_move, 0, NULL, 567: ai_move, 0, NULL, 568: ai_move, 0, NULL, 569: ai_move, 0, NULL, 570: ai_move, 0, NULL 571: }; 572: mmove_t mutant_move_death2 = {FRAME_death201, FRAME_death210, mutant_frames_death2, mutant_dead}; 573: 574: void mutant_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 575: { 576: int n; 577: 578: if (self->health <= self->gib_health) 579: { 580: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 581: for (n= 0; n < 2; n++) 582: ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); 583: for (n= 0; n < 4; n++) 584: ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 585: ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 586: self->deadflag = DEAD_DEAD; 587: return; 588: } 589: 590: if (self->deadflag == DEAD_DEAD) 591: return; 592: 593: gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0); 594: self->deadflag = DEAD_DEAD; 595: self->takedamage = DAMAGE_YES; 596: self->s.skinnum = 1; 597: 598: if (random() < 0.5) 599: self->monsterinfo.currentmove = &mutant_move_death1; 600: else 601: self->monsterinfo.currentmove = &mutant_move_death2; 602: } 603: 604: 605: // 606: // SPAWN 607: // 608: 609: /*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight 610: */ 611: void SP_monster_mutant (edict_t *self) 612: { 613: if (deathmatch->value) 614: { 615: G_FreeEdict (self); 616: return; 617: } 618: 619: sound_swing = gi.soundindex ("mutant/mutatck1.wav"); 620: sound_hit = gi.soundindex ("mutant/mutatck2.wav"); 621: sound_hit2 = gi.soundindex ("mutant/mutatck3.wav"); 622: sound_death = gi.soundindex ("mutant/mutdeth1.wav"); 623: sound_idle = gi.soundindex ("mutant/mutidle1.wav"); 624: sound_pain1 = gi.soundindex ("mutant/mutpain1.wav"); 625: sound_pain2 = gi.soundindex ("mutant/mutpain2.wav"); 626: sound_sight = gi.soundindex ("mutant/mutsght1.wav"); 627: sound_search = gi.soundindex ("mutant/mutsrch1.wav"); 628: sound_step1 = gi.soundindex ("mutant/step1.wav"); 629: sound_step2 = gi.soundindex ("mutant/step2.wav"); 630: sound_step3 = gi.soundindex ("mutant/step3.wav"); 631: sound_thud = gi.soundindex ("mutant/thud1.wav"); 632: 633: self->movetype = MOVETYPE_STEP; 634: self->solid = SOLID_BBOX; 635: self->s.modelindex = gi.modelindex ("models/monsters/mutant/tris.md2"); 636: VectorSet (self->mins, -32, -32, -24); 637: VectorSet (self->maxs, 32, 32, 48); 638: 639: self->health = 300; 640: self->gib_health = -120; 641: self->mass = 300; 642: 643: self->pain = mutant_pain; 644: self->die = mutant_die; 645: 646: self->monsterinfo.stand = mutant_stand; 647: self->monsterinfo.walk = mutant_walk; 648: self->monsterinfo.run = mutant_run; 649: self->monsterinfo.dodge = NULL; 650: self->monsterinfo.attack = mutant_jump; 651: self->monsterinfo.melee = mutant_melee; 652: self->monsterinfo.sight = mutant_sight; 653: self->monsterinfo.search = mutant_search; 654: self->monsterinfo.idle = mutant_idle; 655: self->monsterinfo.checkattack = mutant_checkattack; 656: 657: gi.linkentity (self); 658: 659: self->monsterinfo.currentmove = &mutant_move_stand; 660: 661: self->monsterinfo.scale = MODEL_SCALE; 662: walkmonster_start (self); 663: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.