m_soldier.c (29053B)
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 SOLDIER 24 25 ============================================================================== 26 */ 27 28 #include "g_local.h" 29 #include "m_soldier.h" 30 31 32 static int sound_idle; 33 static int sound_sight1; 34 static int sound_sight2; 35 static int sound_pain_light; 36 static int sound_pain; 37 static int sound_pain_ss; 38 static int sound_death_light; 39 static int sound_death; 40 static int sound_death_ss; 41 static int sound_cock; 42 43 44 void soldier_idle (edict_t *self) 45 { 46 if (random() > 0.8) 47 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0); 48 } 49 50 void soldier_cock (edict_t *self) 51 { 52 if (self->s.frame == FRAME_stand322) 53 gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0); 54 else 55 gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0); 56 } 57 58 59 // STAND 60 61 void soldier_stand (edict_t *self); 62 63 mframe_t soldier_frames_stand1 [] = 64 { 65 ai_stand, 0, soldier_idle, 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 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 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 ai_stand, 0, NULL 97 }; 98 mmove_t soldier_move_stand1 = {FRAME_stand101, FRAME_stand130, soldier_frames_stand1, soldier_stand}; 99 100 mframe_t soldier_frames_stand3 [] = 101 { 102 ai_stand, 0, NULL, 103 ai_stand, 0, NULL, 104 ai_stand, 0, NULL, 105 ai_stand, 0, NULL, 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 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 124 ai_stand, 0, NULL, 125 ai_stand, 0, soldier_cock, 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 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 }; 145 mmove_t soldier_move_stand3 = {FRAME_stand301, FRAME_stand339, soldier_frames_stand3, soldier_stand}; 146 147 #if 0 148 mframe_t soldier_frames_stand4 [] = 149 { 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 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 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 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 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, 4, NULL, 201 ai_stand, 1, NULL, 202 ai_stand, -1, NULL, 203 ai_stand, -2, NULL, 204 205 ai_stand, 0, NULL, 206 ai_stand, 0, NULL 207 }; 208 mmove_t soldier_move_stand4 = {FRAME_stand401, FRAME_stand452, soldier_frames_stand4, NULL}; 209 #endif 210 211 void soldier_stand (edict_t *self) 212 { 213 if ((self->monsterinfo.currentmove == &soldier_move_stand3) || (random() < 0.8)) 214 self->monsterinfo.currentmove = &soldier_move_stand1; 215 else 216 self->monsterinfo.currentmove = &soldier_move_stand3; 217 } 218 219 220 // 221 // WALK 222 // 223 224 void soldier_walk1_random (edict_t *self) 225 { 226 if (random() > 0.1) 227 self->monsterinfo.nextframe = FRAME_walk101; 228 } 229 230 mframe_t soldier_frames_walk1 [] = 231 { 232 ai_walk, 3, NULL, 233 ai_walk, 6, NULL, 234 ai_walk, 2, NULL, 235 ai_walk, 2, NULL, 236 ai_walk, 2, NULL, 237 ai_walk, 1, NULL, 238 ai_walk, 6, NULL, 239 ai_walk, 5, NULL, 240 ai_walk, 3, NULL, 241 ai_walk, -1, soldier_walk1_random, 242 ai_walk, 0, NULL, 243 ai_walk, 0, NULL, 244 ai_walk, 0, NULL, 245 ai_walk, 0, NULL, 246 ai_walk, 0, NULL, 247 ai_walk, 0, NULL, 248 ai_walk, 0, NULL, 249 ai_walk, 0, NULL, 250 ai_walk, 0, NULL, 251 ai_walk, 0, NULL, 252 ai_walk, 0, NULL, 253 ai_walk, 0, NULL, 254 ai_walk, 0, NULL, 255 ai_walk, 0, NULL, 256 ai_walk, 0, NULL, 257 ai_walk, 0, NULL, 258 ai_walk, 0, NULL, 259 ai_walk, 0, NULL, 260 ai_walk, 0, NULL, 261 ai_walk, 0, NULL, 262 ai_walk, 0, NULL, 263 ai_walk, 0, NULL, 264 ai_walk, 0, NULL 265 }; 266 mmove_t soldier_move_walk1 = {FRAME_walk101, FRAME_walk133, soldier_frames_walk1, NULL}; 267 268 mframe_t soldier_frames_walk2 [] = 269 { 270 ai_walk, 4, NULL, 271 ai_walk, 4, NULL, 272 ai_walk, 9, NULL, 273 ai_walk, 8, NULL, 274 ai_walk, 5, NULL, 275 ai_walk, 1, NULL, 276 ai_walk, 3, NULL, 277 ai_walk, 7, NULL, 278 ai_walk, 6, NULL, 279 ai_walk, 7, NULL 280 }; 281 mmove_t soldier_move_walk2 = {FRAME_walk209, FRAME_walk218, soldier_frames_walk2, NULL}; 282 283 void soldier_walk (edict_t *self) 284 { 285 if (random() < 0.5) 286 self->monsterinfo.currentmove = &soldier_move_walk1; 287 else 288 self->monsterinfo.currentmove = &soldier_move_walk2; 289 } 290 291 292 // 293 // RUN 294 // 295 296 void soldier_run (edict_t *self); 297 298 mframe_t soldier_frames_start_run [] = 299 { 300 ai_run, 7, NULL, 301 ai_run, 5, NULL 302 }; 303 mmove_t soldier_move_start_run = {FRAME_run01, FRAME_run02, soldier_frames_start_run, soldier_run}; 304 305 mframe_t soldier_frames_run [] = 306 { 307 ai_run, 10, NULL, 308 ai_run, 11, NULL, 309 ai_run, 11, NULL, 310 ai_run, 16, NULL, 311 ai_run, 10, NULL, 312 ai_run, 15, NULL 313 }; 314 mmove_t soldier_move_run = {FRAME_run03, FRAME_run08, soldier_frames_run, NULL}; 315 316 void soldier_run (edict_t *self) 317 { 318 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 319 { 320 self->monsterinfo.currentmove = &soldier_move_stand1; 321 return; 322 } 323 324 if (self->monsterinfo.currentmove == &soldier_move_walk1 || 325 self->monsterinfo.currentmove == &soldier_move_walk2 || 326 self->monsterinfo.currentmove == &soldier_move_start_run) 327 { 328 self->monsterinfo.currentmove = &soldier_move_run; 329 } 330 else 331 { 332 self->monsterinfo.currentmove = &soldier_move_start_run; 333 } 334 } 335 336 337 // 338 // PAIN 339 // 340 341 mframe_t soldier_frames_pain1 [] = 342 { 343 ai_move, -3, NULL, 344 ai_move, 4, NULL, 345 ai_move, 1, NULL, 346 ai_move, 1, NULL, 347 ai_move, 0, NULL 348 }; 349 mmove_t soldier_move_pain1 = {FRAME_pain101, FRAME_pain105, soldier_frames_pain1, soldier_run}; 350 351 mframe_t soldier_frames_pain2 [] = 352 { 353 ai_move, -13, NULL, 354 ai_move, -1, NULL, 355 ai_move, 2, NULL, 356 ai_move, 4, NULL, 357 ai_move, 2, NULL, 358 ai_move, 3, NULL, 359 ai_move, 2, NULL 360 }; 361 mmove_t soldier_move_pain2 = {FRAME_pain201, FRAME_pain207, soldier_frames_pain2, soldier_run}; 362 363 mframe_t soldier_frames_pain3 [] = 364 { 365 ai_move, -8, NULL, 366 ai_move, 10, NULL, 367 ai_move, -4, NULL, 368 ai_move, -1, NULL, 369 ai_move, -3, NULL, 370 ai_move, 0, NULL, 371 ai_move, 3, NULL, 372 ai_move, 0, NULL, 373 ai_move, 0, NULL, 374 ai_move, 0, NULL, 375 ai_move, 0, NULL, 376 ai_move, 1, NULL, 377 ai_move, 0, NULL, 378 ai_move, 1, NULL, 379 ai_move, 2, NULL, 380 ai_move, 4, NULL, 381 ai_move, 3, NULL, 382 ai_move, 2, NULL 383 }; 384 mmove_t soldier_move_pain3 = {FRAME_pain301, FRAME_pain318, soldier_frames_pain3, soldier_run}; 385 386 mframe_t soldier_frames_pain4 [] = 387 { 388 ai_move, 0, NULL, 389 ai_move, 0, NULL, 390 ai_move, 0, NULL, 391 ai_move, -10, NULL, 392 ai_move, -6, NULL, 393 ai_move, 8, NULL, 394 ai_move, 4, NULL, 395 ai_move, 1, NULL, 396 ai_move, 0, NULL, 397 ai_move, 2, NULL, 398 ai_move, 5, NULL, 399 ai_move, 2, NULL, 400 ai_move, -1, NULL, 401 ai_move, -1, NULL, 402 ai_move, 3, NULL, 403 ai_move, 2, NULL, 404 ai_move, 0, NULL 405 }; 406 mmove_t soldier_move_pain4 = {FRAME_pain401, FRAME_pain417, soldier_frames_pain4, soldier_run}; 407 408 409 void soldier_pain (edict_t *self, edict_t *other, float kick, int damage) 410 { 411 float r; 412 int n; 413 414 if (self->health < (self->max_health / 2)) 415 self->s.skinnum |= 1; 416 417 if (level.time < self->pain_debounce_time) 418 { 419 if ((self->velocity[2] > 100) && ( (self->monsterinfo.currentmove == &soldier_move_pain1) || (self->monsterinfo.currentmove == &soldier_move_pain2) || (self->monsterinfo.currentmove == &soldier_move_pain3))) 420 self->monsterinfo.currentmove = &soldier_move_pain4; 421 return; 422 } 423 424 self->pain_debounce_time = level.time + 3; 425 426 n = self->s.skinnum | 1; 427 if (n == 1) 428 gi.sound (self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0); 429 else if (n == 3) 430 gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0); 431 else 432 gi.sound (self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0); 433 434 if (self->velocity[2] > 100) 435 { 436 self->monsterinfo.currentmove = &soldier_move_pain4; 437 return; 438 } 439 440 if (skill->value == 3) 441 return; // no pain anims in nightmare 442 443 r = random(); 444 445 if (r < 0.33) 446 self->monsterinfo.currentmove = &soldier_move_pain1; 447 else if (r < 0.66) 448 self->monsterinfo.currentmove = &soldier_move_pain2; 449 else 450 self->monsterinfo.currentmove = &soldier_move_pain3; 451 } 452 453 454 // 455 // ATTACK 456 // 457 458 static int blaster_flash [] = {MZ2_SOLDIER_BLASTER_1, MZ2_SOLDIER_BLASTER_2, MZ2_SOLDIER_BLASTER_3, MZ2_SOLDIER_BLASTER_4, MZ2_SOLDIER_BLASTER_5, MZ2_SOLDIER_BLASTER_6, MZ2_SOLDIER_BLASTER_7, MZ2_SOLDIER_BLASTER_8}; 459 static int shotgun_flash [] = {MZ2_SOLDIER_SHOTGUN_1, MZ2_SOLDIER_SHOTGUN_2, MZ2_SOLDIER_SHOTGUN_3, MZ2_SOLDIER_SHOTGUN_4, MZ2_SOLDIER_SHOTGUN_5, MZ2_SOLDIER_SHOTGUN_6, MZ2_SOLDIER_SHOTGUN_7, MZ2_SOLDIER_SHOTGUN_8}; 460 static int machinegun_flash [] = {MZ2_SOLDIER_MACHINEGUN_1, MZ2_SOLDIER_MACHINEGUN_2, MZ2_SOLDIER_MACHINEGUN_3, MZ2_SOLDIER_MACHINEGUN_4, MZ2_SOLDIER_MACHINEGUN_5, MZ2_SOLDIER_MACHINEGUN_6, MZ2_SOLDIER_MACHINEGUN_7, MZ2_SOLDIER_MACHINEGUN_8}; 461 462 void soldier_fire (edict_t *self, int flash_number) 463 { 464 vec3_t start; 465 vec3_t forward, right, up; 466 vec3_t aim; 467 vec3_t dir; 468 vec3_t end; 469 float r, u; 470 int flash_index; 471 472 if (self->s.skinnum < 2) 473 flash_index = blaster_flash[flash_number]; 474 else if (self->s.skinnum < 4) 475 flash_index = shotgun_flash[flash_number]; 476 else 477 flash_index = machinegun_flash[flash_number]; 478 479 AngleVectors (self->s.angles, forward, right, NULL); 480 G_ProjectSource (self->s.origin, monster_flash_offset[flash_index], forward, right, start); 481 482 if (flash_number == 5 || flash_number == 6) 483 { 484 VectorCopy (forward, aim); 485 } 486 else 487 { 488 VectorCopy (self->enemy->s.origin, end); 489 end[2] += self->enemy->viewheight; 490 VectorSubtract (end, start, aim); 491 vectoangles (aim, dir); 492 AngleVectors (dir, forward, right, up); 493 494 r = crandom()*1000; 495 u = crandom()*500; 496 VectorMA (start, 8192, forward, end); 497 VectorMA (end, r, right, end); 498 VectorMA (end, u, up, end); 499 500 VectorSubtract (end, start, aim); 501 VectorNormalize (aim); 502 } 503 504 if (self->s.skinnum <= 1) 505 { 506 monster_fire_blaster (self, start, aim, 5, 600, flash_index, EF_BLASTER); 507 } 508 else if (self->s.skinnum <= 3) 509 { 510 monster_fire_shotgun (self, start, aim, 2, 1, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SHOTGUN_COUNT, flash_index); 511 } 512 else 513 { 514 if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME)) 515 self->monsterinfo.pausetime = level.time + (3 + rand() % 8) * FRAMETIME; 516 517 monster_fire_bullet (self, start, aim, 2, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_index); 518 519 if (level.time >= self->monsterinfo.pausetime) 520 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; 521 else 522 self->monsterinfo.aiflags |= AI_HOLD_FRAME; 523 } 524 } 525 526 // ATTACK1 (blaster/shotgun) 527 528 void soldier_fire1 (edict_t *self) 529 { 530 soldier_fire (self, 0); 531 } 532 533 void soldier_attack1_refire1 (edict_t *self) 534 { 535 if (self->s.skinnum > 1) 536 return; 537 538 if (self->enemy->health <= 0) 539 return; 540 541 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) 542 self->monsterinfo.nextframe = FRAME_attak102; 543 else 544 self->monsterinfo.nextframe = FRAME_attak110; 545 } 546 547 void soldier_attack1_refire2 (edict_t *self) 548 { 549 if (self->s.skinnum < 2) 550 return; 551 552 if (self->enemy->health <= 0) 553 return; 554 555 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) 556 self->monsterinfo.nextframe = FRAME_attak102; 557 } 558 559 mframe_t soldier_frames_attack1 [] = 560 { 561 ai_charge, 0, NULL, 562 ai_charge, 0, NULL, 563 ai_charge, 0, soldier_fire1, 564 ai_charge, 0, NULL, 565 ai_charge, 0, NULL, 566 ai_charge, 0, soldier_attack1_refire1, 567 ai_charge, 0, NULL, 568 ai_charge, 0, soldier_cock, 569 ai_charge, 0, soldier_attack1_refire2, 570 ai_charge, 0, NULL, 571 ai_charge, 0, NULL, 572 ai_charge, 0, NULL 573 }; 574 mmove_t soldier_move_attack1 = {FRAME_attak101, FRAME_attak112, soldier_frames_attack1, soldier_run}; 575 576 // ATTACK2 (blaster/shotgun) 577 578 void soldier_fire2 (edict_t *self) 579 { 580 soldier_fire (self, 1); 581 } 582 583 void soldier_attack2_refire1 (edict_t *self) 584 { 585 if (self->s.skinnum > 1) 586 return; 587 588 if (self->enemy->health <= 0) 589 return; 590 591 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) 592 self->monsterinfo.nextframe = FRAME_attak204; 593 else 594 self->monsterinfo.nextframe = FRAME_attak216; 595 } 596 597 void soldier_attack2_refire2 (edict_t *self) 598 { 599 if (self->s.skinnum < 2) 600 return; 601 602 if (self->enemy->health <= 0) 603 return; 604 605 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) 606 self->monsterinfo.nextframe = FRAME_attak204; 607 } 608 609 mframe_t soldier_frames_attack2 [] = 610 { 611 ai_charge, 0, NULL, 612 ai_charge, 0, NULL, 613 ai_charge, 0, NULL, 614 ai_charge, 0, NULL, 615 ai_charge, 0, soldier_fire2, 616 ai_charge, 0, NULL, 617 ai_charge, 0, NULL, 618 ai_charge, 0, soldier_attack2_refire1, 619 ai_charge, 0, NULL, 620 ai_charge, 0, NULL, 621 ai_charge, 0, NULL, 622 ai_charge, 0, NULL, 623 ai_charge, 0, soldier_cock, 624 ai_charge, 0, NULL, 625 ai_charge, 0, soldier_attack2_refire2, 626 ai_charge, 0, NULL, 627 ai_charge, 0, NULL, 628 ai_charge, 0, NULL 629 }; 630 mmove_t soldier_move_attack2 = {FRAME_attak201, FRAME_attak218, soldier_frames_attack2, soldier_run}; 631 632 // ATTACK3 (duck and shoot) 633 634 void soldier_duck_down (edict_t *self) 635 { 636 if (self->monsterinfo.aiflags & AI_DUCKED) 637 return; 638 self->monsterinfo.aiflags |= AI_DUCKED; 639 self->maxs[2] -= 32; 640 self->takedamage = DAMAGE_YES; 641 self->monsterinfo.pausetime = level.time + 1; 642 gi.linkentity (self); 643 } 644 645 void soldier_duck_up (edict_t *self) 646 { 647 self->monsterinfo.aiflags &= ~AI_DUCKED; 648 self->maxs[2] += 32; 649 self->takedamage = DAMAGE_AIM; 650 gi.linkentity (self); 651 } 652 653 void soldier_fire3 (edict_t *self) 654 { 655 soldier_duck_down (self); 656 soldier_fire (self, 2); 657 } 658 659 void soldier_attack3_refire (edict_t *self) 660 { 661 if ((level.time + 0.4) < self->monsterinfo.pausetime) 662 self->monsterinfo.nextframe = FRAME_attak303; 663 } 664 665 mframe_t soldier_frames_attack3 [] = 666 { 667 ai_charge, 0, NULL, 668 ai_charge, 0, NULL, 669 ai_charge, 0, soldier_fire3, 670 ai_charge, 0, NULL, 671 ai_charge, 0, NULL, 672 ai_charge, 0, soldier_attack3_refire, 673 ai_charge, 0, soldier_duck_up, 674 ai_charge, 0, NULL, 675 ai_charge, 0, NULL 676 }; 677 mmove_t soldier_move_attack3 = {FRAME_attak301, FRAME_attak309, soldier_frames_attack3, soldier_run}; 678 679 // ATTACK4 (machinegun) 680 681 void soldier_fire4 (edict_t *self) 682 { 683 soldier_fire (self, 3); 684 // 685 // if (self->enemy->health <= 0) 686 // return; 687 // 688 // if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) 689 // self->monsterinfo.nextframe = FRAME_attak402; 690 } 691 692 mframe_t soldier_frames_attack4 [] = 693 { 694 ai_charge, 0, NULL, 695 ai_charge, 0, NULL, 696 ai_charge, 0, soldier_fire4, 697 ai_charge, 0, NULL, 698 ai_charge, 0, NULL, 699 ai_charge, 0, NULL 700 }; 701 mmove_t soldier_move_attack4 = {FRAME_attak401, FRAME_attak406, soldier_frames_attack4, soldier_run}; 702 703 #if 0 704 // ATTACK5 (prone) 705 706 void soldier_fire5 (edict_t *self) 707 { 708 soldier_fire (self, 4); 709 } 710 711 void soldier_attack5_refire (edict_t *self) 712 { 713 if (self->enemy->health <= 0) 714 return; 715 716 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) 717 self->monsterinfo.nextframe = FRAME_attak505; 718 } 719 720 mframe_t soldier_frames_attack5 [] = 721 { 722 ai_charge, 8, NULL, 723 ai_charge, 8, NULL, 724 ai_charge, 0, NULL, 725 ai_charge, 0, NULL, 726 ai_charge, 0, soldier_fire5, 727 ai_charge, 0, NULL, 728 ai_charge, 0, NULL, 729 ai_charge, 0, soldier_attack5_refire 730 }; 731 mmove_t soldier_move_attack5 = {FRAME_attak501, FRAME_attak508, soldier_frames_attack5, soldier_run}; 732 #endif 733 734 // ATTACK6 (run & shoot) 735 736 void soldier_fire8 (edict_t *self) 737 { 738 soldier_fire (self, 7); 739 } 740 741 void soldier_attack6_refire (edict_t *self) 742 { 743 if (self->enemy->health <= 0) 744 return; 745 746 if (range(self, self->enemy) < RANGE_MID) 747 return; 748 749 if (skill->value == 3) 750 self->monsterinfo.nextframe = FRAME_runs03; 751 } 752 753 mframe_t soldier_frames_attack6 [] = 754 { 755 ai_charge, 10, NULL, 756 ai_charge, 4, NULL, 757 ai_charge, 12, NULL, 758 ai_charge, 11, soldier_fire8, 759 ai_charge, 13, NULL, 760 ai_charge, 18, NULL, 761 ai_charge, 15, NULL, 762 ai_charge, 14, NULL, 763 ai_charge, 11, NULL, 764 ai_charge, 8, NULL, 765 ai_charge, 11, NULL, 766 ai_charge, 12, NULL, 767 ai_charge, 12, NULL, 768 ai_charge, 17, soldier_attack6_refire 769 }; 770 mmove_t soldier_move_attack6 = {FRAME_runs01, FRAME_runs14, soldier_frames_attack6, soldier_run}; 771 772 void soldier_attack(edict_t *self) 773 { 774 if (self->s.skinnum < 4) 775 { 776 if (random() < 0.5) 777 self->monsterinfo.currentmove = &soldier_move_attack1; 778 else 779 self->monsterinfo.currentmove = &soldier_move_attack2; 780 } 781 else 782 { 783 self->monsterinfo.currentmove = &soldier_move_attack4; 784 } 785 } 786 787 788 // 789 // SIGHT 790 // 791 792 void soldier_sight(edict_t *self, edict_t *other) 793 { 794 if (random() < 0.5) 795 gi.sound (self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0); 796 else 797 gi.sound (self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0); 798 799 if ((skill->value > 0) && (range(self, self->enemy) >= RANGE_MID)) 800 { 801 if (random() > 0.5) 802 self->monsterinfo.currentmove = &soldier_move_attack6; 803 } 804 } 805 806 // 807 // DUCK 808 // 809 810 void soldier_duck_hold (edict_t *self) 811 { 812 if (level.time >= self->monsterinfo.pausetime) 813 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; 814 else 815 self->monsterinfo.aiflags |= AI_HOLD_FRAME; 816 } 817 818 mframe_t soldier_frames_duck [] = 819 { 820 ai_move, 5, soldier_duck_down, 821 ai_move, -1, soldier_duck_hold, 822 ai_move, 1, NULL, 823 ai_move, 0, soldier_duck_up, 824 ai_move, 5, NULL 825 }; 826 mmove_t soldier_move_duck = {FRAME_duck01, FRAME_duck05, soldier_frames_duck, soldier_run}; 827 828 void soldier_dodge (edict_t *self, edict_t *attacker, float eta) 829 { 830 float r; 831 832 r = random(); 833 if (r > 0.25) 834 return; 835 836 if (!self->enemy) 837 self->enemy = attacker; 838 839 if (skill->value == 0) 840 { 841 self->monsterinfo.currentmove = &soldier_move_duck; 842 return; 843 } 844 845 self->monsterinfo.pausetime = level.time + eta + 0.3; 846 r = random(); 847 848 if (skill->value == 1) 849 { 850 if (r > 0.33) 851 self->monsterinfo.currentmove = &soldier_move_duck; 852 else 853 self->monsterinfo.currentmove = &soldier_move_attack3; 854 return; 855 } 856 857 if (skill->value >= 2) 858 { 859 if (r > 0.66) 860 self->monsterinfo.currentmove = &soldier_move_duck; 861 else 862 self->monsterinfo.currentmove = &soldier_move_attack3; 863 return; 864 } 865 866 self->monsterinfo.currentmove = &soldier_move_attack3; 867 } 868 869 870 // 871 // DEATH 872 // 873 874 void soldier_fire6 (edict_t *self) 875 { 876 soldier_fire (self, 5); 877 } 878 879 void soldier_fire7 (edict_t *self) 880 { 881 soldier_fire (self, 6); 882 } 883 884 void soldier_dead (edict_t *self) 885 { 886 VectorSet (self->mins, -16, -16, -24); 887 VectorSet (self->maxs, 16, 16, -8); 888 self->movetype = MOVETYPE_TOSS; 889 self->svflags |= SVF_DEADMONSTER; 890 self->nextthink = 0; 891 gi.linkentity (self); 892 } 893 894 mframe_t soldier_frames_death1 [] = 895 { 896 ai_move, 0, NULL, 897 ai_move, -10, NULL, 898 ai_move, -10, NULL, 899 ai_move, -10, NULL, 900 ai_move, -5, NULL, 901 ai_move, 0, NULL, 902 ai_move, 0, NULL, 903 ai_move, 0, NULL, 904 ai_move, 0, NULL, 905 ai_move, 0, NULL, 906 907 ai_move, 0, NULL, 908 ai_move, 0, NULL, 909 ai_move, 0, NULL, 910 ai_move, 0, NULL, 911 ai_move, 0, NULL, 912 ai_move, 0, NULL, 913 ai_move, 0, NULL, 914 ai_move, 0, NULL, 915 ai_move, 0, NULL, 916 ai_move, 0, NULL, 917 918 ai_move, 0, NULL, 919 ai_move, 0, soldier_fire6, 920 ai_move, 0, NULL, 921 ai_move, 0, NULL, 922 ai_move, 0, soldier_fire7, 923 ai_move, 0, NULL, 924 ai_move, 0, NULL, 925 ai_move, 0, NULL, 926 ai_move, 0, NULL, 927 ai_move, 0, NULL, 928 929 ai_move, 0, NULL, 930 ai_move, 0, NULL, 931 ai_move, 0, NULL, 932 ai_move, 0, NULL, 933 ai_move, 0, NULL, 934 ai_move, 0, NULL 935 }; 936 mmove_t soldier_move_death1 = {FRAME_death101, FRAME_death136, soldier_frames_death1, soldier_dead}; 937 938 mframe_t soldier_frames_death2 [] = 939 { 940 ai_move, -5, NULL, 941 ai_move, -5, NULL, 942 ai_move, -5, NULL, 943 ai_move, 0, NULL, 944 ai_move, 0, NULL, 945 ai_move, 0, NULL, 946 ai_move, 0, NULL, 947 ai_move, 0, NULL, 948 ai_move, 0, NULL, 949 ai_move, 0, NULL, 950 951 ai_move, 0, NULL, 952 ai_move, 0, NULL, 953 ai_move, 0, NULL, 954 ai_move, 0, NULL, 955 ai_move, 0, NULL, 956 ai_move, 0, NULL, 957 ai_move, 0, NULL, 958 ai_move, 0, NULL, 959 ai_move, 0, NULL, 960 ai_move, 0, NULL, 961 962 ai_move, 0, NULL, 963 ai_move, 0, NULL, 964 ai_move, 0, NULL, 965 ai_move, 0, NULL, 966 ai_move, 0, NULL, 967 ai_move, 0, NULL, 968 ai_move, 0, NULL, 969 ai_move, 0, NULL, 970 ai_move, 0, NULL, 971 ai_move, 0, NULL, 972 973 ai_move, 0, NULL, 974 ai_move, 0, NULL, 975 ai_move, 0, NULL, 976 ai_move, 0, NULL, 977 ai_move, 0, NULL 978 }; 979 mmove_t soldier_move_death2 = {FRAME_death201, FRAME_death235, soldier_frames_death2, soldier_dead}; 980 981 mframe_t soldier_frames_death3 [] = 982 { 983 ai_move, -5, NULL, 984 ai_move, -5, NULL, 985 ai_move, -5, NULL, 986 ai_move, 0, NULL, 987 ai_move, 0, NULL, 988 ai_move, 0, NULL, 989 ai_move, 0, NULL, 990 ai_move, 0, NULL, 991 ai_move, 0, NULL, 992 ai_move, 0, NULL, 993 994 ai_move, 0, NULL, 995 ai_move, 0, NULL, 996 ai_move, 0, NULL, 997 ai_move, 0, NULL, 998 ai_move, 0, NULL, 999 ai_move, 0, NULL, 1000 ai_move, 0, NULL, 1001 ai_move, 0, NULL, 1002 ai_move, 0, NULL, 1003 ai_move, 0, NULL, 1004 1005 ai_move, 0, NULL, 1006 ai_move, 0, NULL, 1007 ai_move, 0, NULL, 1008 ai_move, 0, NULL, 1009 ai_move, 0, NULL, 1010 ai_move, 0, NULL, 1011 ai_move, 0, NULL, 1012 ai_move, 0, NULL, 1013 ai_move, 0, NULL, 1014 ai_move, 0, NULL, 1015 1016 ai_move, 0, NULL, 1017 ai_move, 0, NULL, 1018 ai_move, 0, NULL, 1019 ai_move, 0, NULL, 1020 ai_move, 0, NULL, 1021 ai_move, 0, NULL, 1022 ai_move, 0, NULL, 1023 ai_move, 0, NULL, 1024 ai_move, 0, NULL, 1025 ai_move, 0, NULL, 1026 1027 ai_move, 0, NULL, 1028 ai_move, 0, NULL, 1029 ai_move, 0, NULL, 1030 ai_move, 0, NULL, 1031 ai_move, 0, NULL, 1032 }; 1033 mmove_t soldier_move_death3 = {FRAME_death301, FRAME_death345, soldier_frames_death3, soldier_dead}; 1034 1035 mframe_t soldier_frames_death4 [] = 1036 { 1037 ai_move, 0, NULL, 1038 ai_move, 0, NULL, 1039 ai_move, 0, NULL, 1040 ai_move, 0, NULL, 1041 ai_move, 0, NULL, 1042 ai_move, 0, NULL, 1043 ai_move, 0, NULL, 1044 ai_move, 0, NULL, 1045 ai_move, 0, NULL, 1046 ai_move, 0, NULL, 1047 1048 ai_move, 0, NULL, 1049 ai_move, 0, NULL, 1050 ai_move, 0, NULL, 1051 ai_move, 0, NULL, 1052 ai_move, 0, NULL, 1053 ai_move, 0, NULL, 1054 ai_move, 0, NULL, 1055 ai_move, 0, NULL, 1056 ai_move, 0, NULL, 1057 ai_move, 0, NULL, 1058 1059 ai_move, 0, NULL, 1060 ai_move, 0, NULL, 1061 ai_move, 0, NULL, 1062 ai_move, 0, NULL, 1063 ai_move, 0, NULL, 1064 ai_move, 0, NULL, 1065 ai_move, 0, NULL, 1066 ai_move, 0, NULL, 1067 ai_move, 0, NULL, 1068 ai_move, 0, NULL, 1069 1070 ai_move, 0, NULL, 1071 ai_move, 0, NULL, 1072 ai_move, 0, NULL, 1073 ai_move, 0, NULL, 1074 ai_move, 0, NULL, 1075 ai_move, 0, NULL, 1076 ai_move, 0, NULL, 1077 ai_move, 0, NULL, 1078 ai_move, 0, NULL, 1079 ai_move, 0, NULL, 1080 1081 ai_move, 0, NULL, 1082 ai_move, 0, NULL, 1083 ai_move, 0, NULL, 1084 ai_move, 0, NULL, 1085 ai_move, 0, NULL, 1086 ai_move, 0, NULL, 1087 ai_move, 0, NULL, 1088 ai_move, 0, NULL, 1089 ai_move, 0, NULL, 1090 ai_move, 0, NULL, 1091 1092 ai_move, 0, NULL, 1093 ai_move, 0, NULL, 1094 ai_move, 0, NULL 1095 }; 1096 mmove_t soldier_move_death4 = {FRAME_death401, FRAME_death453, soldier_frames_death4, soldier_dead}; 1097 1098 mframe_t soldier_frames_death5 [] = 1099 { 1100 ai_move, -5, NULL, 1101 ai_move, -5, NULL, 1102 ai_move, -5, NULL, 1103 ai_move, 0, NULL, 1104 ai_move, 0, NULL, 1105 ai_move, 0, NULL, 1106 ai_move, 0, NULL, 1107 ai_move, 0, NULL, 1108 ai_move, 0, NULL, 1109 ai_move, 0, NULL, 1110 1111 ai_move, 0, NULL, 1112 ai_move, 0, NULL, 1113 ai_move, 0, NULL, 1114 ai_move, 0, NULL, 1115 ai_move, 0, NULL, 1116 ai_move, 0, NULL, 1117 ai_move, 0, NULL, 1118 ai_move, 0, NULL, 1119 ai_move, 0, NULL, 1120 ai_move, 0, NULL, 1121 1122 ai_move, 0, NULL, 1123 ai_move, 0, NULL, 1124 ai_move, 0, NULL, 1125 ai_move, 0, NULL 1126 }; 1127 mmove_t soldier_move_death5 = {FRAME_death501, FRAME_death524, soldier_frames_death5, soldier_dead}; 1128 1129 mframe_t soldier_frames_death6 [] = 1130 { 1131 ai_move, 0, NULL, 1132 ai_move, 0, NULL, 1133 ai_move, 0, NULL, 1134 ai_move, 0, NULL, 1135 ai_move, 0, NULL, 1136 ai_move, 0, NULL, 1137 ai_move, 0, NULL, 1138 ai_move, 0, NULL, 1139 ai_move, 0, NULL, 1140 ai_move, 0, NULL 1141 }; 1142 mmove_t soldier_move_death6 = {FRAME_death601, FRAME_death610, soldier_frames_death6, soldier_dead}; 1143 1144 void soldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 1145 { 1146 int n; 1147 1148 // check for gib 1149 if (self->health <= self->gib_health) 1150 { 1151 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 1152 for (n= 0; n < 3; n++) 1153 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 1154 ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC); 1155 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 1156 self->deadflag = DEAD_DEAD; 1157 return; 1158 } 1159 1160 if (self->deadflag == DEAD_DEAD) 1161 return; 1162 1163 // regular death 1164 self->deadflag = DEAD_DEAD; 1165 self->takedamage = DAMAGE_YES; 1166 self->s.skinnum |= 1; 1167 1168 if (self->s.skinnum == 1) 1169 gi.sound (self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0); 1170 else if (self->s.skinnum == 3) 1171 gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0); 1172 else // (self->s.skinnum == 5) 1173 gi.sound (self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0); 1174 1175 if (fabs((self->s.origin[2] + self->viewheight) - point[2]) <= 4) 1176 { 1177 // head shot 1178 self->monsterinfo.currentmove = &soldier_move_death3; 1179 return; 1180 } 1181 1182 n = rand() % 5; 1183 if (n == 0) 1184 self->monsterinfo.currentmove = &soldier_move_death1; 1185 else if (n == 1) 1186 self->monsterinfo.currentmove = &soldier_move_death2; 1187 else if (n == 2) 1188 self->monsterinfo.currentmove = &soldier_move_death4; 1189 else if (n == 3) 1190 self->monsterinfo.currentmove = &soldier_move_death5; 1191 else 1192 self->monsterinfo.currentmove = &soldier_move_death6; 1193 } 1194 1195 1196 // 1197 // SPAWN 1198 // 1199 1200 void SP_monster_soldier_x (edict_t *self) 1201 { 1202 1203 self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2"); 1204 self->monsterinfo.scale = MODEL_SCALE; 1205 VectorSet (self->mins, -16, -16, -24); 1206 VectorSet (self->maxs, 16, 16, 32); 1207 self->movetype = MOVETYPE_STEP; 1208 self->solid = SOLID_BBOX; 1209 1210 sound_idle = gi.soundindex ("soldier/solidle1.wav"); 1211 sound_sight1 = gi.soundindex ("soldier/solsght1.wav"); 1212 sound_sight2 = gi.soundindex ("soldier/solsrch1.wav"); 1213 sound_cock = gi.soundindex ("infantry/infatck3.wav"); 1214 1215 self->mass = 100; 1216 1217 self->pain = soldier_pain; 1218 self->die = soldier_die; 1219 1220 self->monsterinfo.stand = soldier_stand; 1221 self->monsterinfo.walk = soldier_walk; 1222 self->monsterinfo.run = soldier_run; 1223 self->monsterinfo.dodge = soldier_dodge; 1224 self->monsterinfo.attack = soldier_attack; 1225 self->monsterinfo.melee = NULL; 1226 self->monsterinfo.sight = soldier_sight; 1227 1228 gi.linkentity (self); 1229 1230 self->monsterinfo.stand (self); 1231 1232 walkmonster_start (self); 1233 } 1234 1235 1236 /*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 1237 */ 1238 void SP_monster_soldier_light (edict_t *self) 1239 { 1240 if (deathmatch->value) 1241 { 1242 G_FreeEdict (self); 1243 return; 1244 } 1245 1246 SP_monster_soldier_x (self); 1247 1248 sound_pain_light = gi.soundindex ("soldier/solpain2.wav"); 1249 sound_death_light = gi.soundindex ("soldier/soldeth2.wav"); 1250 gi.modelindex ("models/objects/laser/tris.md2"); 1251 gi.soundindex ("misc/lasfly.wav"); 1252 gi.soundindex ("soldier/solatck2.wav"); 1253 1254 self->s.skinnum = 0; 1255 self->health = 20; 1256 self->gib_health = -30; 1257 } 1258 1259 /*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 1260 */ 1261 void SP_monster_soldier (edict_t *self) 1262 { 1263 if (deathmatch->value) 1264 { 1265 G_FreeEdict (self); 1266 return; 1267 } 1268 1269 SP_monster_soldier_x (self); 1270 1271 sound_pain = gi.soundindex ("soldier/solpain1.wav"); 1272 sound_death = gi.soundindex ("soldier/soldeth1.wav"); 1273 gi.soundindex ("soldier/solatck1.wav"); 1274 1275 self->s.skinnum = 2; 1276 self->health = 30; 1277 self->gib_health = -30; 1278 } 1279 1280 /*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 1281 */ 1282 void SP_monster_soldier_ss (edict_t *self) 1283 { 1284 if (deathmatch->value) 1285 { 1286 G_FreeEdict (self); 1287 return; 1288 } 1289 1290 SP_monster_soldier_x (self); 1291 1292 sound_pain_ss = gi.soundindex ("soldier/solpain3.wav"); 1293 sound_death_ss = gi.soundindex ("soldier/soldeth3.wav"); 1294 gi.soundindex ("soldier/solatck3.wav"); 1295 1296 self->s.skinnum = 4; 1297 self->health = 40; 1298 self->gib_health = -30; 1299 }