m_infantry.c (14651B)
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 INFANTRY 24 25 ============================================================================== 26 */ 27 28 #include "g_local.h" 29 #include "m_infantry.h" 30 31 void InfantryMachineGun (edict_t *self); 32 33 34 static int sound_pain1; 35 static int sound_pain2; 36 static int sound_die1; 37 static int sound_die2; 38 39 static int sound_gunshot; 40 static int sound_weapon_cock; 41 static int sound_punch_swing; 42 static int sound_punch_hit; 43 static int sound_sight; 44 static int sound_search; 45 static int sound_idle; 46 47 48 mframe_t infantry_frames_stand [] = 49 { 50 ai_stand, 0, NULL, 51 ai_stand, 0, NULL, 52 ai_stand, 0, NULL, 53 ai_stand, 0, NULL, 54 ai_stand, 0, NULL, 55 ai_stand, 0, NULL, 56 ai_stand, 0, NULL, 57 ai_stand, 0, NULL, 58 ai_stand, 0, NULL, 59 ai_stand, 0, NULL, 60 ai_stand, 0, NULL, 61 ai_stand, 0, NULL, 62 ai_stand, 0, NULL, 63 ai_stand, 0, NULL, 64 ai_stand, 0, NULL, 65 ai_stand, 0, NULL, 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 }; 73 mmove_t infantry_move_stand = {FRAME_stand50, FRAME_stand71, infantry_frames_stand, NULL}; 74 75 void infantry_stand (edict_t *self) 76 { 77 self->monsterinfo.currentmove = &infantry_move_stand; 78 } 79 80 81 mframe_t infantry_frames_fidget [] = 82 { 83 ai_stand, 1, NULL, 84 ai_stand, 0, NULL, 85 ai_stand, 1, NULL, 86 ai_stand, 3, NULL, 87 ai_stand, 6, NULL, 88 ai_stand, 3, NULL, 89 ai_stand, 0, NULL, 90 ai_stand, 0, NULL, 91 ai_stand, 0, NULL, 92 ai_stand, 0, NULL, 93 ai_stand, 1, NULL, 94 ai_stand, 0, NULL, 95 ai_stand, 0, NULL, 96 ai_stand, 0, NULL, 97 ai_stand, 0, NULL, 98 ai_stand, 1, NULL, 99 ai_stand, 0, NULL, 100 ai_stand, -1, NULL, 101 ai_stand, 0, NULL, 102 ai_stand, 0, NULL, 103 ai_stand, 1, NULL, 104 ai_stand, 0, NULL, 105 ai_stand, -2, NULL, 106 ai_stand, 1, NULL, 107 ai_stand, 1, NULL, 108 ai_stand, 1, NULL, 109 ai_stand, -1, NULL, 110 ai_stand, 0, NULL, 111 ai_stand, 0, NULL, 112 ai_stand, -1, 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, -1, NULL, 119 ai_stand, 0, NULL, 120 ai_stand, 0, NULL, 121 ai_stand, 1, NULL, 122 ai_stand, 0, NULL, 123 ai_stand, 0, NULL, 124 ai_stand, -1, NULL, 125 ai_stand, -1, NULL, 126 ai_stand, 0, NULL, 127 ai_stand, -3, NULL, 128 ai_stand, -2, NULL, 129 ai_stand, -3, NULL, 130 ai_stand, -3, NULL, 131 ai_stand, -2, NULL 132 }; 133 mmove_t infantry_move_fidget = {FRAME_stand01, FRAME_stand49, infantry_frames_fidget, infantry_stand}; 134 135 void infantry_fidget (edict_t *self) 136 { 137 self->monsterinfo.currentmove = &infantry_move_fidget; 138 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0); 139 } 140 141 mframe_t infantry_frames_walk [] = 142 { 143 ai_walk, 5, NULL, 144 ai_walk, 4, NULL, 145 ai_walk, 4, NULL, 146 ai_walk, 5, NULL, 147 ai_walk, 4, NULL, 148 ai_walk, 5, NULL, 149 ai_walk, 6, NULL, 150 ai_walk, 4, NULL, 151 ai_walk, 4, NULL, 152 ai_walk, 4, NULL, 153 ai_walk, 4, NULL, 154 ai_walk, 5, NULL 155 }; 156 mmove_t infantry_move_walk = {FRAME_walk03, FRAME_walk14, infantry_frames_walk, NULL}; 157 158 void infantry_walk (edict_t *self) 159 { 160 self->monsterinfo.currentmove = &infantry_move_walk; 161 } 162 163 mframe_t infantry_frames_run [] = 164 { 165 ai_run, 10, NULL, 166 ai_run, 20, NULL, 167 ai_run, 5, NULL, 168 ai_run, 7, NULL, 169 ai_run, 30, NULL, 170 ai_run, 35, NULL, 171 ai_run, 2, NULL, 172 ai_run, 6, NULL 173 }; 174 mmove_t infantry_move_run = {FRAME_run01, FRAME_run08, infantry_frames_run, NULL}; 175 176 void infantry_run (edict_t *self) 177 { 178 if (self->monsterinfo.aiflags & AI_STAND_GROUND) 179 self->monsterinfo.currentmove = &infantry_move_stand; 180 else 181 self->monsterinfo.currentmove = &infantry_move_run; 182 } 183 184 185 mframe_t infantry_frames_pain1 [] = 186 { 187 ai_move, -3, NULL, 188 ai_move, -2, NULL, 189 ai_move, -1, NULL, 190 ai_move, -2, NULL, 191 ai_move, -1, NULL, 192 ai_move, 1, NULL, 193 ai_move, -1, NULL, 194 ai_move, 1, NULL, 195 ai_move, 6, NULL, 196 ai_move, 2, NULL 197 }; 198 mmove_t infantry_move_pain1 = {FRAME_pain101, FRAME_pain110, infantry_frames_pain1, infantry_run}; 199 200 mframe_t infantry_frames_pain2 [] = 201 { 202 ai_move, -3, NULL, 203 ai_move, -3, NULL, 204 ai_move, 0, NULL, 205 ai_move, -1, NULL, 206 ai_move, -2, NULL, 207 ai_move, 0, NULL, 208 ai_move, 0, NULL, 209 ai_move, 2, NULL, 210 ai_move, 5, NULL, 211 ai_move, 2, NULL 212 }; 213 mmove_t infantry_move_pain2 = {FRAME_pain201, FRAME_pain210, infantry_frames_pain2, infantry_run}; 214 215 void infantry_pain (edict_t *self, edict_t *other, float kick, int damage) 216 { 217 int n; 218 219 if (self->health < (self->max_health / 2)) 220 self->s.skinnum = 1; 221 222 if (level.time < self->pain_debounce_time) 223 return; 224 225 self->pain_debounce_time = level.time + 3; 226 227 if (skill->value == 3) 228 return; // no pain anims in nightmare 229 230 n = rand() % 2; 231 if (n == 0) 232 { 233 self->monsterinfo.currentmove = &infantry_move_pain1; 234 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0); 235 } 236 else 237 { 238 self->monsterinfo.currentmove = &infantry_move_pain2; 239 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0); 240 } 241 } 242 243 244 vec3_t aimangles[] = 245 { 246 0.0, 5.0, 0.0, 247 10.0, 15.0, 0.0, 248 20.0, 25.0, 0.0, 249 25.0, 35.0, 0.0, 250 30.0, 40.0, 0.0, 251 30.0, 45.0, 0.0, 252 25.0, 50.0, 0.0, 253 20.0, 40.0, 0.0, 254 15.0, 35.0, 0.0, 255 40.0, 35.0, 0.0, 256 70.0, 35.0, 0.0, 257 90.0, 35.0, 0.0 258 }; 259 260 void InfantryMachineGun (edict_t *self) 261 { 262 vec3_t start, target; 263 vec3_t forward, right; 264 vec3_t vec; 265 int flash_number; 266 267 if (self->s.frame == FRAME_attak111) 268 { 269 flash_number = MZ2_INFANTRY_MACHINEGUN_1; 270 AngleVectors (self->s.angles, forward, right, NULL); 271 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); 272 273 if (self->enemy) 274 { 275 VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target); 276 target[2] += self->enemy->viewheight; 277 VectorSubtract (target, start, forward); 278 VectorNormalize (forward); 279 } 280 else 281 { 282 AngleVectors (self->s.angles, forward, right, NULL); 283 } 284 } 285 else 286 { 287 flash_number = MZ2_INFANTRY_MACHINEGUN_2 + (self->s.frame - FRAME_death211); 288 289 AngleVectors (self->s.angles, forward, right, NULL); 290 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); 291 292 VectorSubtract (self->s.angles, aimangles[flash_number-MZ2_INFANTRY_MACHINEGUN_2], vec); 293 AngleVectors (vec, forward, NULL, NULL); 294 } 295 296 monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number); 297 } 298 299 void infantry_sight (edict_t *self, edict_t *other) 300 { 301 gi.sound (self, CHAN_BODY, sound_sight, 1, ATTN_NORM, 0); 302 } 303 304 void infantry_dead (edict_t *self) 305 { 306 VectorSet (self->mins, -16, -16, -24); 307 VectorSet (self->maxs, 16, 16, -8); 308 self->movetype = MOVETYPE_TOSS; 309 self->svflags |= SVF_DEADMONSTER; 310 gi.linkentity (self); 311 312 M_FlyCheck (self); 313 } 314 315 mframe_t infantry_frames_death1 [] = 316 { 317 ai_move, -4, NULL, 318 ai_move, 0, NULL, 319 ai_move, 0, NULL, 320 ai_move, -1, NULL, 321 ai_move, -4, NULL, 322 ai_move, 0, NULL, 323 ai_move, 0, NULL, 324 ai_move, 0, NULL, 325 ai_move, -1, NULL, 326 ai_move, 3, NULL, 327 ai_move, 1, NULL, 328 ai_move, 1, NULL, 329 ai_move, -2, NULL, 330 ai_move, 2, NULL, 331 ai_move, 2, NULL, 332 ai_move, 9, NULL, 333 ai_move, 9, NULL, 334 ai_move, 5, NULL, 335 ai_move, -3, NULL, 336 ai_move, -3, NULL 337 }; 338 mmove_t infantry_move_death1 = {FRAME_death101, FRAME_death120, infantry_frames_death1, infantry_dead}; 339 340 // Off with his head 341 mframe_t infantry_frames_death2 [] = 342 { 343 ai_move, 0, NULL, 344 ai_move, 1, NULL, 345 ai_move, 5, NULL, 346 ai_move, -1, NULL, 347 ai_move, 0, NULL, 348 ai_move, 1, NULL, 349 ai_move, 1, NULL, 350 ai_move, 4, NULL, 351 ai_move, 3, NULL, 352 ai_move, 0, NULL, 353 ai_move, -2, InfantryMachineGun, 354 ai_move, -2, InfantryMachineGun, 355 ai_move, -3, InfantryMachineGun, 356 ai_move, -1, InfantryMachineGun, 357 ai_move, -2, InfantryMachineGun, 358 ai_move, 0, InfantryMachineGun, 359 ai_move, 2, InfantryMachineGun, 360 ai_move, 2, InfantryMachineGun, 361 ai_move, 3, InfantryMachineGun, 362 ai_move, -10, InfantryMachineGun, 363 ai_move, -7, InfantryMachineGun, 364 ai_move, -8, InfantryMachineGun, 365 ai_move, -6, NULL, 366 ai_move, 4, NULL, 367 ai_move, 0, NULL 368 }; 369 mmove_t infantry_move_death2 = {FRAME_death201, FRAME_death225, infantry_frames_death2, infantry_dead}; 370 371 mframe_t infantry_frames_death3 [] = 372 { 373 ai_move, 0, NULL, 374 ai_move, 0, NULL, 375 ai_move, 0, NULL, 376 ai_move, -6, NULL, 377 ai_move, -11, NULL, 378 ai_move, -3, NULL, 379 ai_move, -11, NULL, 380 ai_move, 0, NULL, 381 ai_move, 0, NULL 382 }; 383 mmove_t infantry_move_death3 = {FRAME_death301, FRAME_death309, infantry_frames_death3, infantry_dead}; 384 385 386 void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 387 { 388 int n; 389 390 // check for gib 391 if (self->health <= self->gib_health) 392 { 393 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 394 for (n= 0; n < 2; n++) 395 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); 396 for (n= 0; n < 4; n++) 397 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 398 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 399 self->deadflag = DEAD_DEAD; 400 return; 401 } 402 403 if (self->deadflag == DEAD_DEAD) 404 return; 405 406 // regular death 407 self->deadflag = DEAD_DEAD; 408 self->takedamage = DAMAGE_YES; 409 410 n = rand() % 3; 411 if (n == 0) 412 { 413 self->monsterinfo.currentmove = &infantry_move_death1; 414 gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0); 415 } 416 else if (n == 1) 417 { 418 self->monsterinfo.currentmove = &infantry_move_death2; 419 gi.sound (self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0); 420 } 421 else 422 { 423 self->monsterinfo.currentmove = &infantry_move_death3; 424 gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0); 425 } 426 } 427 428 429 void infantry_duck_down (edict_t *self) 430 { 431 if (self->monsterinfo.aiflags & AI_DUCKED) 432 return; 433 self->monsterinfo.aiflags |= AI_DUCKED; 434 self->maxs[2] -= 32; 435 self->takedamage = DAMAGE_YES; 436 self->monsterinfo.pausetime = level.time + 1; 437 gi.linkentity (self); 438 } 439 440 void infantry_duck_hold (edict_t *self) 441 { 442 if (level.time >= self->monsterinfo.pausetime) 443 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; 444 else 445 self->monsterinfo.aiflags |= AI_HOLD_FRAME; 446 } 447 448 void infantry_duck_up (edict_t *self) 449 { 450 self->monsterinfo.aiflags &= ~AI_DUCKED; 451 self->maxs[2] += 32; 452 self->takedamage = DAMAGE_AIM; 453 gi.linkentity (self); 454 } 455 456 mframe_t infantry_frames_duck [] = 457 { 458 ai_move, -2, infantry_duck_down, 459 ai_move, -5, infantry_duck_hold, 460 ai_move, 3, NULL, 461 ai_move, 4, infantry_duck_up, 462 ai_move, 0, NULL 463 }; 464 mmove_t infantry_move_duck = {FRAME_duck01, FRAME_duck05, infantry_frames_duck, infantry_run}; 465 466 void infantry_dodge (edict_t *self, edict_t *attacker, float eta) 467 { 468 if (random() > 0.25) 469 return; 470 471 if (!self->enemy) 472 self->enemy = attacker; 473 474 self->monsterinfo.currentmove = &infantry_move_duck; 475 } 476 477 478 void infantry_cock_gun (edict_t *self) 479 { 480 int n; 481 482 gi.sound (self, CHAN_WEAPON, sound_weapon_cock, 1, ATTN_NORM, 0); 483 n = (rand() & 15) + 3 + 7; 484 self->monsterinfo.pausetime = level.time + n * FRAMETIME; 485 } 486 487 void infantry_fire (edict_t *self) 488 { 489 InfantryMachineGun (self); 490 491 if (level.time >= self->monsterinfo.pausetime) 492 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; 493 else 494 self->monsterinfo.aiflags |= AI_HOLD_FRAME; 495 } 496 497 mframe_t infantry_frames_attack1 [] = 498 { 499 ai_charge, 4, NULL, 500 ai_charge, -1, NULL, 501 ai_charge, -1, NULL, 502 ai_charge, 0, infantry_cock_gun, 503 ai_charge, -1, NULL, 504 ai_charge, 1, NULL, 505 ai_charge, 1, NULL, 506 ai_charge, 2, NULL, 507 ai_charge, -2, NULL, 508 ai_charge, -3, NULL, 509 ai_charge, 1, infantry_fire, 510 ai_charge, 5, NULL, 511 ai_charge, -1, NULL, 512 ai_charge, -2, NULL, 513 ai_charge, -3, NULL 514 }; 515 mmove_t infantry_move_attack1 = {FRAME_attak101, FRAME_attak115, infantry_frames_attack1, infantry_run}; 516 517 518 void infantry_swing (edict_t *self) 519 { 520 gi.sound (self, CHAN_WEAPON, sound_punch_swing, 1, ATTN_NORM, 0); 521 } 522 523 void infantry_smack (edict_t *self) 524 { 525 vec3_t aim; 526 527 VectorSet (aim, MELEE_DISTANCE, 0, 0); 528 if (fire_hit (self, aim, (5 + (rand() % 5)), 50)) 529 gi.sound (self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0); 530 } 531 532 mframe_t infantry_frames_attack2 [] = 533 { 534 ai_charge, 3, NULL, 535 ai_charge, 6, NULL, 536 ai_charge, 0, infantry_swing, 537 ai_charge, 8, NULL, 538 ai_charge, 5, NULL, 539 ai_charge, 8, infantry_smack, 540 ai_charge, 6, NULL, 541 ai_charge, 3, NULL, 542 }; 543 mmove_t infantry_move_attack2 = {FRAME_attak201, FRAME_attak208, infantry_frames_attack2, infantry_run}; 544 545 void infantry_attack(edict_t *self) 546 { 547 if (range (self, self->enemy) == RANGE_MELEE) 548 self->monsterinfo.currentmove = &infantry_move_attack2; 549 else 550 self->monsterinfo.currentmove = &infantry_move_attack1; 551 } 552 553 554 /*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 555 */ 556 void SP_monster_infantry (edict_t *self) 557 { 558 if (deathmatch->value) 559 { 560 G_FreeEdict (self); 561 return; 562 } 563 564 sound_pain1 = gi.soundindex ("infantry/infpain1.wav"); 565 sound_pain2 = gi.soundindex ("infantry/infpain2.wav"); 566 sound_die1 = gi.soundindex ("infantry/infdeth1.wav"); 567 sound_die2 = gi.soundindex ("infantry/infdeth2.wav"); 568 569 sound_gunshot = gi.soundindex ("infantry/infatck1.wav"); 570 sound_weapon_cock = gi.soundindex ("infantry/infatck3.wav"); 571 sound_punch_swing = gi.soundindex ("infantry/infatck2.wav"); 572 sound_punch_hit = gi.soundindex ("infantry/melee2.wav"); 573 574 sound_sight = gi.soundindex ("infantry/infsght1.wav"); 575 sound_search = gi.soundindex ("infantry/infsrch1.wav"); 576 sound_idle = gi.soundindex ("infantry/infidle1.wav"); 577 578 579 self->movetype = MOVETYPE_STEP; 580 self->solid = SOLID_BBOX; 581 self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2"); 582 VectorSet (self->mins, -16, -16, -24); 583 VectorSet (self->maxs, 16, 16, 32); 584 585 self->health = 100; 586 self->gib_health = -40; 587 self->mass = 200; 588 589 self->pain = infantry_pain; 590 self->die = infantry_die; 591 592 self->monsterinfo.stand = infantry_stand; 593 self->monsterinfo.walk = infantry_walk; 594 self->monsterinfo.run = infantry_run; 595 self->monsterinfo.dodge = infantry_dodge; 596 self->monsterinfo.attack = infantry_attack; 597 self->monsterinfo.melee = NULL; 598 self->monsterinfo.sight = infantry_sight; 599 self->monsterinfo.idle = infantry_fidget; 600 601 gi.linkentity (self); 602 603 self->monsterinfo.currentmove = &infantry_move_stand; 604 self->monsterinfo.scale = MODEL_SCALE; 605 606 walkmonster_start (self); 607 }