m_chick.c (15888B)
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 chick 24 25 ============================================================================== 26 */ 27 28 #include "g_local.h" 29 #include "m_chick.h" 30 31 qboolean visible (edict_t *self, edict_t *other); 32 33 void chick_stand (edict_t *self); 34 void chick_run (edict_t *self); 35 void chick_reslash(edict_t *self); 36 void chick_rerocket(edict_t *self); 37 void chick_attack1(edict_t *self); 38 39 static int sound_missile_prelaunch; 40 static int sound_missile_launch; 41 static int sound_melee_swing; 42 static int sound_melee_hit; 43 static int sound_missile_reload; 44 static int sound_death1; 45 static int sound_death2; 46 static int sound_fall_down; 47 static int sound_idle1; 48 static int sound_idle2; 49 static int sound_pain1; 50 static int sound_pain2; 51 static int sound_pain3; 52 static int sound_sight; 53 static int sound_search; 54 55 56 void ChickMoan (edict_t *self) 57 { 58 if (random() < 0.5) 59 gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0); 60 else 61 gi.sound (self, CHAN_VOICE, sound_idle2, 1, ATTN_IDLE, 0); 62 } 63 64 mframe_t chick_frames_fidget [] = 65 { 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, ChickMoan, 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 ai_stand, 0, NULL, 94 ai_stand, 0, NULL, 95 ai_stand, 0, NULL 96 }; 97 mmove_t chick_move_fidget = {FRAME_stand201, FRAME_stand230, chick_frames_fidget, chick_stand}; 98 99 void chick_fidget (edict_t *self) 100 { 101 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 102 return; 103 if (random() <= 0.3) 104 self->monsterinfo.currentmove = &chick_move_fidget; 105 } 106 107 mframe_t chick_frames_stand [] = 108 { 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, 116 ai_stand, 0, NULL, 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, 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, chick_fidget, 139 140 }; 141 mmove_t chick_move_stand = {FRAME_stand101, FRAME_stand130, chick_frames_stand, NULL}; 142 143 void chick_stand (edict_t *self) 144 { 145 self->monsterinfo.currentmove = &chick_move_stand; 146 } 147 148 mframe_t chick_frames_start_run [] = 149 { 150 ai_run, 1, NULL, 151 ai_run, 0, NULL, 152 ai_run, 0, NULL, 153 ai_run, -1, NULL, 154 ai_run, -1, NULL, 155 ai_run, 0, NULL, 156 ai_run, 1, NULL, 157 ai_run, 3, NULL, 158 ai_run, 6, NULL, 159 ai_run, 3, NULL 160 }; 161 mmove_t chick_move_start_run = {FRAME_walk01, FRAME_walk10, chick_frames_start_run, chick_run}; 162 163 mframe_t chick_frames_run [] = 164 { 165 ai_run, 6, NULL, 166 ai_run, 8, NULL, 167 ai_run, 13, NULL, 168 ai_run, 5, NULL, 169 ai_run, 7, NULL, 170 ai_run, 4, NULL, 171 ai_run, 11, NULL, 172 ai_run, 5, NULL, 173 ai_run, 9, NULL, 174 ai_run, 7, NULL 175 176 }; 177 178 mmove_t chick_move_run = {FRAME_walk11, FRAME_walk20, chick_frames_run, NULL}; 179 180 mframe_t chick_frames_walk [] = 181 { 182 ai_walk, 6, NULL, 183 ai_walk, 8, NULL, 184 ai_walk, 13, NULL, 185 ai_walk, 5, NULL, 186 ai_walk, 7, NULL, 187 ai_walk, 4, NULL, 188 ai_walk, 11, NULL, 189 ai_walk, 5, NULL, 190 ai_walk, 9, NULL, 191 ai_walk, 7, NULL 192 }; 193 194 mmove_t chick_move_walk = {FRAME_walk11, FRAME_walk20, chick_frames_walk, NULL}; 195 196 void chick_walk (edict_t *self) 197 { 198 self->monsterinfo.currentmove = &chick_move_walk; 199 } 200 201 void chick_run (edict_t *self) 202 { 203 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 204 { 205 self->monsterinfo.currentmove = &chick_move_stand; 206 return; 207 } 208 209 if (self->monsterinfo.currentmove == &chick_move_walk || 210 self->monsterinfo.currentmove == &chick_move_start_run) 211 { 212 self->monsterinfo.currentmove = &chick_move_run; 213 } 214 else 215 { 216 self->monsterinfo.currentmove = &chick_move_start_run; 217 } 218 } 219 220 mframe_t chick_frames_pain1 [] = 221 { 222 ai_move, 0, NULL, 223 ai_move, 0, NULL, 224 ai_move, 0, NULL, 225 ai_move, 0, NULL, 226 ai_move, 0, NULL 227 }; 228 mmove_t chick_move_pain1 = {FRAME_pain101, FRAME_pain105, chick_frames_pain1, chick_run}; 229 230 mframe_t chick_frames_pain2 [] = 231 { 232 ai_move, 0, NULL, 233 ai_move, 0, NULL, 234 ai_move, 0, NULL, 235 ai_move, 0, NULL, 236 ai_move, 0, NULL 237 }; 238 mmove_t chick_move_pain2 = {FRAME_pain201, FRAME_pain205, chick_frames_pain2, chick_run}; 239 240 mframe_t chick_frames_pain3 [] = 241 { 242 ai_move, 0, NULL, 243 ai_move, 0, NULL, 244 ai_move, -6, NULL, 245 ai_move, 3, NULL, 246 ai_move, 11, NULL, 247 ai_move, 3, NULL, 248 ai_move, 0, NULL, 249 ai_move, 0, NULL, 250 ai_move, 4, NULL, 251 ai_move, 1, NULL, 252 ai_move, 0, NULL, 253 ai_move, -3, NULL, 254 ai_move, -4, NULL, 255 ai_move, 5, NULL, 256 ai_move, 7, NULL, 257 ai_move, -2, NULL, 258 ai_move, 3, NULL, 259 ai_move, -5, NULL, 260 ai_move, -2, NULL, 261 ai_move, -8, NULL, 262 ai_move, 2, NULL 263 }; 264 mmove_t chick_move_pain3 = {FRAME_pain301, FRAME_pain321, chick_frames_pain3, chick_run}; 265 266 void chick_pain (edict_t *self, edict_t *other, float kick, int damage) 267 { 268 float r; 269 270 if (self->health < (self->max_health / 2)) 271 self->s.skinnum = 1; 272 273 if (level.time < self->pain_debounce_time) 274 return; 275 276 self->pain_debounce_time = level.time + 3; 277 278 r = random(); 279 if (r < 0.33) 280 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0); 281 else if (r < 0.66) 282 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0); 283 else 284 gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0); 285 286 if (skill->value == 3) 287 return; // no pain anims in nightmare 288 289 if (damage <= 10) 290 self->monsterinfo.currentmove = &chick_move_pain1; 291 else if (damage <= 25) 292 self->monsterinfo.currentmove = &chick_move_pain2; 293 else 294 self->monsterinfo.currentmove = &chick_move_pain3; 295 } 296 297 void chick_dead (edict_t *self) 298 { 299 VectorSet (self->mins, -16, -16, 0); 300 VectorSet (self->maxs, 16, 16, 16); 301 self->movetype = MOVETYPE_TOSS; 302 self->svflags |= SVF_DEADMONSTER; 303 self->nextthink = 0; 304 gi.linkentity (self); 305 } 306 307 mframe_t chick_frames_death2 [] = 308 { 309 ai_move, -6, NULL, 310 ai_move, 0, NULL, 311 ai_move, -1, NULL, 312 ai_move, -5, NULL, 313 ai_move, 0, NULL, 314 ai_move, -1, NULL, 315 ai_move, -2, NULL, 316 ai_move, 1, NULL, 317 ai_move, 10, NULL, 318 ai_move, 2, NULL, 319 ai_move, 3, NULL, 320 ai_move, 1, NULL, 321 ai_move, 2, NULL, 322 ai_move, 0, NULL, 323 ai_move, 3, NULL, 324 ai_move, 3, NULL, 325 ai_move, 1, NULL, 326 ai_move, -3, NULL, 327 ai_move, -5, NULL, 328 ai_move, 4, NULL, 329 ai_move, 15, NULL, 330 ai_move, 14, NULL, 331 ai_move, 1, NULL 332 }; 333 mmove_t chick_move_death2 = {FRAME_death201, FRAME_death223, chick_frames_death2, chick_dead}; 334 335 mframe_t chick_frames_death1 [] = 336 { 337 ai_move, 0, NULL, 338 ai_move, 0, NULL, 339 ai_move, -7, NULL, 340 ai_move, 4, NULL, 341 ai_move, 11, NULL, 342 ai_move, 0, NULL, 343 ai_move, 0, NULL, 344 ai_move, 0, NULL, 345 ai_move, 0, NULL, 346 ai_move, 0, NULL, 347 ai_move, 0, NULL, 348 ai_move, 0, NULL 349 350 }; 351 mmove_t chick_move_death1 = {FRAME_death101, FRAME_death112, chick_frames_death1, chick_dead}; 352 353 void chick_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 354 { 355 int n; 356 357 // check for gib 358 if (self->health <= self->gib_health) 359 { 360 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 361 for (n= 0; n < 2; n++) 362 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); 363 for (n= 0; n < 4; n++) 364 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 365 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 366 self->deadflag = DEAD_DEAD; 367 return; 368 } 369 370 if (self->deadflag == DEAD_DEAD) 371 return; 372 373 // regular death 374 self->deadflag = DEAD_DEAD; 375 self->takedamage = DAMAGE_YES; 376 377 n = rand() % 2; 378 if (n == 0) 379 { 380 self->monsterinfo.currentmove = &chick_move_death1; 381 gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0); 382 } 383 else 384 { 385 self->monsterinfo.currentmove = &chick_move_death2; 386 gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0); 387 } 388 } 389 390 391 void chick_duck_down (edict_t *self) 392 { 393 if (self->monsterinfo.aiflags & AI_DUCKED) 394 return; 395 self->monsterinfo.aiflags |= AI_DUCKED; 396 self->maxs[2] -= 32; 397 self->takedamage = DAMAGE_YES; 398 self->monsterinfo.pausetime = level.time + 1; 399 gi.linkentity (self); 400 } 401 402 void chick_duck_hold (edict_t *self) 403 { 404 if (level.time >= self->monsterinfo.pausetime) 405 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; 406 else 407 self->monsterinfo.aiflags |= AI_HOLD_FRAME; 408 } 409 410 void chick_duck_up (edict_t *self) 411 { 412 self->monsterinfo.aiflags &= ~AI_DUCKED; 413 self->maxs[2] += 32; 414 self->takedamage = DAMAGE_AIM; 415 gi.linkentity (self); 416 } 417 418 mframe_t chick_frames_duck [] = 419 { 420 ai_move, 0, chick_duck_down, 421 ai_move, 1, NULL, 422 ai_move, 4, chick_duck_hold, 423 ai_move, -4, NULL, 424 ai_move, -5, chick_duck_up, 425 ai_move, 3, NULL, 426 ai_move, 1, NULL 427 }; 428 mmove_t chick_move_duck = {FRAME_duck01, FRAME_duck07, chick_frames_duck, chick_run}; 429 430 void chick_dodge (edict_t *self, edict_t *attacker, float eta) 431 { 432 if (random() > 0.25) 433 return; 434 435 if (!self->enemy) 436 self->enemy = attacker; 437 438 self->monsterinfo.currentmove = &chick_move_duck; 439 } 440 441 void ChickSlash (edict_t *self) 442 { 443 vec3_t aim; 444 445 VectorSet (aim, MELEE_DISTANCE, self->mins[0], 10); 446 gi.sound (self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0); 447 fire_hit (self, aim, (10 + (rand() %6)), 100); 448 } 449 450 451 void ChickRocket (edict_t *self) 452 { 453 vec3_t forward, right; 454 vec3_t start; 455 vec3_t dir; 456 vec3_t vec; 457 458 AngleVectors (self->s.angles, forward, right, NULL); 459 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CHICK_ROCKET_1], forward, right, start); 460 461 VectorCopy (self->enemy->s.origin, vec); 462 vec[2] += self->enemy->viewheight; 463 VectorSubtract (vec, start, dir); 464 VectorNormalize (dir); 465 466 monster_fire_rocket (self, start, dir, 50, 500, MZ2_CHICK_ROCKET_1); 467 } 468 469 void Chick_PreAttack1 (edict_t *self) 470 { 471 gi.sound (self, CHAN_VOICE, sound_missile_prelaunch, 1, ATTN_NORM, 0); 472 } 473 474 void ChickReload (edict_t *self) 475 { 476 gi.sound (self, CHAN_VOICE, sound_missile_reload, 1, ATTN_NORM, 0); 477 } 478 479 480 mframe_t chick_frames_start_attack1 [] = 481 { 482 ai_charge, 0, Chick_PreAttack1, 483 ai_charge, 0, NULL, 484 ai_charge, 0, NULL, 485 ai_charge, 4, NULL, 486 ai_charge, 0, NULL, 487 ai_charge, -3, NULL, 488 ai_charge, 3, NULL, 489 ai_charge, 5, NULL, 490 ai_charge, 7, NULL, 491 ai_charge, 0, NULL, 492 ai_charge, 0, NULL, 493 ai_charge, 0, NULL, 494 ai_charge, 0, chick_attack1 495 }; 496 mmove_t chick_move_start_attack1 = {FRAME_attak101, FRAME_attak113, chick_frames_start_attack1, NULL}; 497 498 499 mframe_t chick_frames_attack1 [] = 500 { 501 ai_charge, 19, ChickRocket, 502 ai_charge, -6, NULL, 503 ai_charge, -5, NULL, 504 ai_charge, -2, NULL, 505 ai_charge, -7, NULL, 506 ai_charge, 0, NULL, 507 ai_charge, 1, NULL, 508 ai_charge, 10, ChickReload, 509 ai_charge, 4, NULL, 510 ai_charge, 5, NULL, 511 ai_charge, 6, NULL, 512 ai_charge, 6, NULL, 513 ai_charge, 4, NULL, 514 ai_charge, 3, chick_rerocket 515 516 }; 517 mmove_t chick_move_attack1 = {FRAME_attak114, FRAME_attak127, chick_frames_attack1, NULL}; 518 519 mframe_t chick_frames_end_attack1 [] = 520 { 521 ai_charge, -3, NULL, 522 ai_charge, 0, NULL, 523 ai_charge, -6, NULL, 524 ai_charge, -4, NULL, 525 ai_charge, -2, NULL 526 }; 527 mmove_t chick_move_end_attack1 = {FRAME_attak128, FRAME_attak132, chick_frames_end_attack1, chick_run}; 528 529 void chick_rerocket(edict_t *self) 530 { 531 if (self->enemy->health > 0) 532 { 533 if (range (self, self->enemy) > RANGE_MELEE) 534 if ( visible (self, self->enemy) ) 535 if (random() <= 0.6) 536 { 537 self->monsterinfo.currentmove = &chick_move_attack1; 538 return; 539 } 540 } 541 self->monsterinfo.currentmove = &chick_move_end_attack1; 542 } 543 544 void chick_attack1(edict_t *self) 545 { 546 self->monsterinfo.currentmove = &chick_move_attack1; 547 } 548 549 mframe_t chick_frames_slash [] = 550 { 551 ai_charge, 1, NULL, 552 ai_charge, 7, ChickSlash, 553 ai_charge, -7, NULL, 554 ai_charge, 1, NULL, 555 ai_charge, -1, NULL, 556 ai_charge, 1, NULL, 557 ai_charge, 0, NULL, 558 ai_charge, 1, NULL, 559 ai_charge, -2, chick_reslash 560 }; 561 mmove_t chick_move_slash = {FRAME_attak204, FRAME_attak212, chick_frames_slash, NULL}; 562 563 mframe_t chick_frames_end_slash [] = 564 { 565 ai_charge, -6, NULL, 566 ai_charge, -1, NULL, 567 ai_charge, -6, NULL, 568 ai_charge, 0, NULL 569 }; 570 mmove_t chick_move_end_slash = {FRAME_attak213, FRAME_attak216, chick_frames_end_slash, chick_run}; 571 572 573 void chick_reslash(edict_t *self) 574 { 575 if (self->enemy->health > 0) 576 { 577 if (range (self, self->enemy) == RANGE_MELEE) 578 if (random() <= 0.9) 579 { 580 self->monsterinfo.currentmove = &chick_move_slash; 581 return; 582 } 583 else 584 { 585 self->monsterinfo.currentmove = &chick_move_end_slash; 586 return; 587 } 588 } 589 self->monsterinfo.currentmove = &chick_move_end_slash; 590 } 591 592 void chick_slash(edict_t *self) 593 { 594 self->monsterinfo.currentmove = &chick_move_slash; 595 } 596 597 598 mframe_t chick_frames_start_slash [] = 599 { 600 ai_charge, 1, NULL, 601 ai_charge, 8, NULL, 602 ai_charge, 3, NULL 603 }; 604 mmove_t chick_move_start_slash = {FRAME_attak201, FRAME_attak203, chick_frames_start_slash, chick_slash}; 605 606 607 608 void chick_melee(edict_t *self) 609 { 610 self->monsterinfo.currentmove = &chick_move_start_slash; 611 } 612 613 614 void chick_attack(edict_t *self) 615 { 616 self->monsterinfo.currentmove = &chick_move_start_attack1; 617 } 618 619 void chick_sight(edict_t *self, edict_t *other) 620 { 621 gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); 622 } 623 624 /*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 625 */ 626 void SP_monster_chick (edict_t *self) 627 { 628 if (deathmatch->value) 629 { 630 G_FreeEdict (self); 631 return; 632 } 633 634 sound_missile_prelaunch = gi.soundindex ("chick/chkatck1.wav"); 635 sound_missile_launch = gi.soundindex ("chick/chkatck2.wav"); 636 sound_melee_swing = gi.soundindex ("chick/chkatck3.wav"); 637 sound_melee_hit = gi.soundindex ("chick/chkatck4.wav"); 638 sound_missile_reload = gi.soundindex ("chick/chkatck5.wav"); 639 sound_death1 = gi.soundindex ("chick/chkdeth1.wav"); 640 sound_death2 = gi.soundindex ("chick/chkdeth2.wav"); 641 sound_fall_down = gi.soundindex ("chick/chkfall1.wav"); 642 sound_idle1 = gi.soundindex ("chick/chkidle1.wav"); 643 sound_idle2 = gi.soundindex ("chick/chkidle2.wav"); 644 sound_pain1 = gi.soundindex ("chick/chkpain1.wav"); 645 sound_pain2 = gi.soundindex ("chick/chkpain2.wav"); 646 sound_pain3 = gi.soundindex ("chick/chkpain3.wav"); 647 sound_sight = gi.soundindex ("chick/chksght1.wav"); 648 sound_search = gi.soundindex ("chick/chksrch1.wav"); 649 650 self->movetype = MOVETYPE_STEP; 651 self->solid = SOLID_BBOX; 652 self->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2"); 653 VectorSet (self->mins, -16, -16, 0); 654 VectorSet (self->maxs, 16, 16, 56); 655 656 self->health = 175; 657 self->gib_health = -70; 658 self->mass = 200; 659 660 self->pain = chick_pain; 661 self->die = chick_die; 662 663 self->monsterinfo.stand = chick_stand; 664 self->monsterinfo.walk = chick_walk; 665 self->monsterinfo.run = chick_run; 666 self->monsterinfo.dodge = chick_dodge; 667 self->monsterinfo.attack = chick_attack; 668 self->monsterinfo.melee = chick_melee; 669 self->monsterinfo.sight = chick_sight; 670 671 gi.linkentity (self); 672 673 self->monsterinfo.currentmove = &chick_move_stand; 674 self->monsterinfo.scale = MODEL_SCALE; 675 676 walkmonster_start (self); 677 }