m_mutant.c (14658B)
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 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 }