|
|
1.1 ! root 1: /* ! 2: ============================================================================== ! 3: ! 4: SOLDIER ! 5: ! 6: ============================================================================== ! 7: */ ! 8: ! 9: #include "g_local.h" ! 10: #include "m_soldier.h" ! 11: ! 12: //ROGUE ! 13: #define RUN_SHOOT 1 ! 14: #define CHECK_TARGET 1 ! 15: //ROGUE ! 16: ! 17: static int sound_idle; ! 18: static int sound_sight1; ! 19: static int sound_sight2; ! 20: static int sound_pain_light; ! 21: static int sound_pain; ! 22: static int sound_pain_ss; ! 23: static int sound_death_light; ! 24: static int sound_death; ! 25: static int sound_death_ss; ! 26: static int sound_cock; ! 27: ! 28: void soldier_duck_up (edict_t *self); ! 29: ! 30: void soldier_start_charge (edict_t *self) ! 31: { ! 32: self->monsterinfo.aiflags |= AI_CHARGING; ! 33: } ! 34: ! 35: void soldier_stop_charge (edict_t *self) ! 36: { ! 37: self->monsterinfo.aiflags &= ~AI_CHARGING; ! 38: } ! 39: ! 40: void soldier_idle (edict_t *self) ! 41: { ! 42: if (random() > 0.8) ! 43: gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0); ! 44: } ! 45: ! 46: void soldier_cock (edict_t *self) ! 47: { ! 48: if (self->s.frame == FRAME_stand322) ! 49: gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0); ! 50: else ! 51: gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0); ! 52: } ! 53: ! 54: ! 55: // STAND ! 56: ! 57: void soldier_stand (edict_t *self); ! 58: ! 59: mframe_t soldier_frames_stand1 [] = ! 60: { ! 61: ai_stand, 0, soldier_idle, ! 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: ! 72: ai_stand, 0, NULL, ! 73: ai_stand, 0, NULL, ! 74: ai_stand, 0, NULL, ! 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: ! 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: }; ! 94: mmove_t soldier_move_stand1 = {FRAME_stand101, FRAME_stand130, soldier_frames_stand1, soldier_stand}; ! 95: ! 96: mframe_t soldier_frames_stand3 [] = ! 97: { ! 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, ! 105: ai_stand, 0, NULL, ! 106: ai_stand, 0, NULL, ! 107: ai_stand, 0, NULL, ! 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: ! 120: ai_stand, 0, NULL, ! 121: ai_stand, 0, soldier_cock, ! 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: ! 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, NULL, ! 139: ai_stand, 0, NULL ! 140: }; ! 141: mmove_t soldier_move_stand3 = {FRAME_stand301, FRAME_stand339, soldier_frames_stand3, soldier_stand}; ! 142: ! 143: #if 0 ! 144: mframe_t soldier_frames_stand4 [] = ! 145: { ! 146: ai_stand, 0, NULL, ! 147: ai_stand, 0, NULL, ! 148: ai_stand, 0, NULL, ! 149: ai_stand, 0, NULL, ! 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: ! 157: ai_stand, 0, NULL, ! 158: ai_stand, 0, NULL, ! 159: ai_stand, 0, NULL, ! 160: ai_stand, 0, NULL, ! 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: ! 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: ai_stand, 0, NULL, ! 175: ai_stand, 0, NULL, ! 176: ai_stand, 0, NULL, ! 177: ai_stand, 0, NULL, ! 178: ! 179: ai_stand, 0, NULL, ! 180: ai_stand, 0, NULL, ! 181: ai_stand, 0, NULL, ! 182: ai_stand, 0, NULL, ! 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: ! 190: ai_stand, 0, NULL, ! 191: ai_stand, 0, NULL, ! 192: ai_stand, 0, NULL, ! 193: ai_stand, 0, NULL, ! 194: ai_stand, 0, NULL, ! 195: ai_stand, 0, NULL, ! 196: ai_stand, 4, NULL, ! 197: ai_stand, 1, NULL, ! 198: ai_stand, -1, NULL, ! 199: ai_stand, -2, NULL, ! 200: ! 201: ai_stand, 0, NULL, ! 202: ai_stand, 0, NULL ! 203: }; ! 204: mmove_t soldier_move_stand4 = {FRAME_stand401, FRAME_stand452, soldier_frames_stand4, NULL}; ! 205: #endif ! 206: ! 207: void soldier_stand (edict_t *self) ! 208: { ! 209: if ((self->monsterinfo.currentmove == &soldier_move_stand3) || (random() < 0.8)) ! 210: self->monsterinfo.currentmove = &soldier_move_stand1; ! 211: else ! 212: self->monsterinfo.currentmove = &soldier_move_stand3; ! 213: } ! 214: ! 215: ! 216: // ! 217: // WALK ! 218: // ! 219: ! 220: void soldier_walk1_random (edict_t *self) ! 221: { ! 222: if (random() > 0.1) ! 223: self->monsterinfo.nextframe = FRAME_walk101; ! 224: } ! 225: ! 226: mframe_t soldier_frames_walk1 [] = ! 227: { ! 228: ai_walk, 3, NULL, ! 229: ai_walk, 6, NULL, ! 230: ai_walk, 2, NULL, ! 231: ai_walk, 2, NULL, ! 232: ai_walk, 2, NULL, ! 233: ai_walk, 1, NULL, ! 234: ai_walk, 6, NULL, ! 235: ai_walk, 5, NULL, ! 236: ai_walk, 3, NULL, ! 237: ai_walk, -1, soldier_walk1_random, ! 238: ai_walk, 0, NULL, ! 239: ai_walk, 0, NULL, ! 240: ai_walk, 0, NULL, ! 241: ai_walk, 0, NULL, ! 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: }; ! 262: mmove_t soldier_move_walk1 = {FRAME_walk101, FRAME_walk133, soldier_frames_walk1, NULL}; ! 263: ! 264: mframe_t soldier_frames_walk2 [] = ! 265: { ! 266: ai_walk, 4, NULL, ! 267: ai_walk, 4, NULL, ! 268: ai_walk, 9, NULL, ! 269: ai_walk, 8, NULL, ! 270: ai_walk, 5, NULL, ! 271: ai_walk, 1, NULL, ! 272: ai_walk, 3, NULL, ! 273: ai_walk, 7, NULL, ! 274: ai_walk, 6, NULL, ! 275: ai_walk, 7, NULL ! 276: }; ! 277: mmove_t soldier_move_walk2 = {FRAME_walk209, FRAME_walk218, soldier_frames_walk2, NULL}; ! 278: ! 279: void soldier_walk (edict_t *self) ! 280: { ! 281: if (random() < 0.5) ! 282: self->monsterinfo.currentmove = &soldier_move_walk1; ! 283: else ! 284: self->monsterinfo.currentmove = &soldier_move_walk2; ! 285: } ! 286: ! 287: ! 288: // ! 289: // RUN ! 290: // ! 291: ! 292: void soldier_run (edict_t *self); ! 293: ! 294: mframe_t soldier_frames_start_run [] = ! 295: { ! 296: ai_run, 7, NULL, ! 297: ai_run, 5, NULL ! 298: }; ! 299: mmove_t soldier_move_start_run = {FRAME_run01, FRAME_run02, soldier_frames_start_run, soldier_run}; ! 300: ! 301: #ifdef RUN_SHOOT ! 302: void soldier_fire (edict_t *self, int); ! 303: ! 304: void soldier_fire_run (edict_t *self) { ! 305: if ((self->s.skinnum <= 1) && (self->enemy) && visible(self, self->enemy)) { ! 306: soldier_fire(self, 0); ! 307: } ! 308: } ! 309: #endif ! 310: ! 311: mframe_t soldier_frames_run [] = ! 312: { ! 313: ai_run, 10, NULL, ! 314: ai_run, 11, monster_done_dodge, ! 315: ai_run, 11, NULL, ! 316: ai_run, 16, NULL, ! 317: ai_run, 10, NULL, ! 318: ai_run, 15, monster_done_dodge ! 319: }; ! 320: ! 321: mmove_t soldier_move_run = {FRAME_run03, FRAME_run08, soldier_frames_run, NULL}; ! 322: ! 323: void soldier_run (edict_t *self) ! 324: { ! 325: monster_done_dodge (self); ! 326: ! 327: if (self->monsterinfo.aiflags & AI_STAND_GROUND) ! 328: { ! 329: self->monsterinfo.currentmove = &soldier_move_stand1; ! 330: return; ! 331: } ! 332: ! 333: if (self->monsterinfo.currentmove == &soldier_move_walk1 || ! 334: self->monsterinfo.currentmove == &soldier_move_walk2 || ! 335: self->monsterinfo.currentmove == &soldier_move_start_run) ! 336: { ! 337: self->monsterinfo.currentmove = &soldier_move_run; ! 338: } ! 339: else ! 340: { ! 341: self->monsterinfo.currentmove = &soldier_move_start_run; ! 342: } ! 343: } ! 344: ! 345: ! 346: // ! 347: // PAIN ! 348: // ! 349: ! 350: mframe_t soldier_frames_pain1 [] = ! 351: { ! 352: ai_move, -3, NULL, ! 353: ai_move, 4, NULL, ! 354: ai_move, 1, NULL, ! 355: ai_move, 1, NULL, ! 356: ai_move, 0, NULL ! 357: }; ! 358: mmove_t soldier_move_pain1 = {FRAME_pain101, FRAME_pain105, soldier_frames_pain1, soldier_run}; ! 359: ! 360: mframe_t soldier_frames_pain2 [] = ! 361: { ! 362: ai_move, -13, NULL, ! 363: ai_move, -1, NULL, ! 364: ai_move, 2, NULL, ! 365: ai_move, 4, NULL, ! 366: ai_move, 2, NULL, ! 367: ai_move, 3, NULL, ! 368: ai_move, 2, NULL ! 369: }; ! 370: mmove_t soldier_move_pain2 = {FRAME_pain201, FRAME_pain207, soldier_frames_pain2, soldier_run}; ! 371: ! 372: mframe_t soldier_frames_pain3 [] = ! 373: { ! 374: ai_move, -8, NULL, ! 375: ai_move, 10, NULL, ! 376: ai_move, -4, NULL, ! 377: ai_move, -1, NULL, ! 378: ai_move, -3, NULL, ! 379: ai_move, 0, NULL, ! 380: ai_move, 3, NULL, ! 381: ai_move, 0, NULL, ! 382: ai_move, 0, NULL, ! 383: ai_move, 0, NULL, ! 384: ai_move, 0, NULL, ! 385: ai_move, 1, NULL, ! 386: ai_move, 0, NULL, ! 387: ai_move, 1, NULL, ! 388: ai_move, 2, NULL, ! 389: ai_move, 4, NULL, ! 390: ai_move, 3, NULL, ! 391: ai_move, 2, NULL ! 392: }; ! 393: mmove_t soldier_move_pain3 = {FRAME_pain301, FRAME_pain318, soldier_frames_pain3, soldier_run}; ! 394: ! 395: mframe_t soldier_frames_pain4 [] = ! 396: { ! 397: ai_move, 0, NULL, ! 398: ai_move, 0, NULL, ! 399: ai_move, 0, NULL, ! 400: ai_move, -10, NULL, ! 401: ai_move, -6, NULL, ! 402: ai_move, 8, NULL, ! 403: ai_move, 4, NULL, ! 404: ai_move, 1, NULL, ! 405: ai_move, 0, NULL, ! 406: ai_move, 2, NULL, ! 407: ai_move, 5, NULL, ! 408: ai_move, 2, NULL, ! 409: ai_move, -1, NULL, ! 410: ai_move, -1, NULL, ! 411: ai_move, 3, NULL, ! 412: ai_move, 2, NULL, ! 413: ai_move, 0, NULL ! 414: }; ! 415: mmove_t soldier_move_pain4 = {FRAME_pain401, FRAME_pain417, soldier_frames_pain4, soldier_run}; ! 416: ! 417: ! 418: void soldier_pain (edict_t *self, edict_t *other, float kick, int damage) ! 419: { ! 420: float r; ! 421: int n; ! 422: ! 423: if (self->health < (self->max_health / 2)) ! 424: self->s.skinnum |= 1; ! 425: ! 426: monster_done_dodge (self); ! 427: soldier_stop_charge(self); ! 428: ! 429: // if we're blind firing, this needs to be turned off here ! 430: self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING; ! 431: ! 432: if (level.time < self->pain_debounce_time) ! 433: { ! 434: if ((self->velocity[2] > 100) && ( (self->monsterinfo.currentmove == &soldier_move_pain1) || (self->monsterinfo.currentmove == &soldier_move_pain2) || (self->monsterinfo.currentmove == &soldier_move_pain3))) ! 435: { ! 436: // PMM - clear duck flag ! 437: if (self->monsterinfo.aiflags & AI_DUCKED) ! 438: monster_duck_up(self); ! 439: self->monsterinfo.currentmove = &soldier_move_pain4; ! 440: } ! 441: return; ! 442: } ! 443: ! 444: self->pain_debounce_time = level.time + 3; ! 445: ! 446: n = self->s.skinnum | 1; ! 447: if (n == 1) ! 448: gi.sound (self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0); ! 449: else if (n == 3) ! 450: gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0); ! 451: else ! 452: gi.sound (self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0); ! 453: ! 454: if (self->velocity[2] > 100) ! 455: { ! 456: // PMM - clear duck flag ! 457: if (self->monsterinfo.aiflags & AI_DUCKED) ! 458: monster_duck_up(self); ! 459: self->monsterinfo.currentmove = &soldier_move_pain4; ! 460: self->monsterinfo.pausetime = 0; ! 461: return; ! 462: } ! 463: ! 464: if (skill->value == 3) ! 465: return; // no pain anims in nightmare ! 466: ! 467: r = random(); ! 468: ! 469: if (r < 0.33) ! 470: self->monsterinfo.currentmove = &soldier_move_pain1; ! 471: else if (r < 0.66) ! 472: self->monsterinfo.currentmove = &soldier_move_pain2; ! 473: else ! 474: self->monsterinfo.currentmove = &soldier_move_pain3; ! 475: ! 476: // PMM - clear duck flag ! 477: if (self->monsterinfo.aiflags & AI_DUCKED) ! 478: monster_duck_up(self); ! 479: self->monsterinfo.pausetime = 0; ! 480: ! 481: } ! 482: ! 483: ! 484: // ! 485: // ATTACK ! 486: // ! 487: ! 488: 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}; ! 489: 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}; ! 490: 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}; ! 491: ! 492: //void soldier_fire (edict_t *self, int flash_number) PMM ! 493: void soldier_fire (edict_t *self, int in_flash_number) ! 494: { ! 495: vec3_t start; ! 496: vec3_t forward, right, up; ! 497: vec3_t aim; ! 498: vec3_t dir; ! 499: vec3_t end; ! 500: float r, u; ! 501: int flash_index; ! 502: int flash_number; ! 503: #ifdef RUN_SHOOT ! 504: vec3_t aim_norm; ! 505: float angle; ! 506: #endif ! 507: #ifdef CHECK_TARGET ! 508: trace_t tr; ! 509: vec3_t aim_good; ! 510: #endif ! 511: ! 512: if ((!self->enemy) || (!self->enemy->inuse)) ! 513: return; ! 514: ! 515: if (in_flash_number < 0) ! 516: { ! 517: flash_number = -1 * in_flash_number; ! 518: } ! 519: else ! 520: flash_number = in_flash_number; ! 521: ! 522: if (self->s.skinnum < 2) ! 523: flash_index = blaster_flash[flash_number]; ! 524: else if (self->s.skinnum < 4) ! 525: flash_index = shotgun_flash[flash_number]; ! 526: else ! 527: flash_index = machinegun_flash[flash_number]; ! 528: ! 529: AngleVectors (self->s.angles, forward, right, NULL); ! 530: G_ProjectSource (self->s.origin, monster_flash_offset[flash_index], forward, right, start); ! 531: ! 532: if (flash_number == 5 || flash_number == 6) // he's dead ! 533: { ! 534: VectorCopy (forward, aim); ! 535: } ! 536: else ! 537: { ! 538: VectorCopy (self->enemy->s.origin, end); ! 539: end[2] += self->enemy->viewheight; ! 540: VectorSubtract (end, start, aim); ! 541: #ifdef CHECK_TARGET ! 542: VectorCopy (end, aim_good); ! 543: #endif ! 544: #ifdef RUN_SHOOT ! 545: //PMM ! 546: if (in_flash_number < 0) ! 547: { ! 548: VectorCopy (aim, aim_norm); ! 549: VectorNormalize (aim_norm); ! 550: angle = DotProduct (aim_norm, forward); ! 551: //gi.dprintf ("Dot Product: %f", DotProduct (aim_norm, forward)); ! 552: if (angle < 0.9) // ~25 degree angle ! 553: { ! 554: // if(g_showlogic && g_showlogic->value) ! 555: // gi.dprintf (" not firing due to bad dotprod %f\n", angle); ! 556: return; ! 557: } else { ! 558: // if(g_showlogic && g_showlogic->value) ! 559: // gi.dprintf (" firing: dotprod = %f\n", angle); ! 560: } ! 561: } ! 562: //-PMM ! 563: #endif ! 564: vectoangles (aim, dir); ! 565: AngleVectors (dir, forward, right, up); ! 566: ! 567: if (skill->value < 2) ! 568: { ! 569: r = crandom()*1000; ! 570: u = crandom()*500; ! 571: } ! 572: else ! 573: { ! 574: r = crandom()*500; ! 575: u = crandom()*250; ! 576: } ! 577: VectorMA (start, 8192, forward, end); ! 578: VectorMA (end, r, right, end); ! 579: VectorMA (end, u, up, end); ! 580: ! 581: VectorSubtract (end, start, aim); ! 582: VectorNormalize (aim); ! 583: } ! 584: #ifdef CHECK_TARGET ! 585: if (!(flash_number == 5 || flash_number == 6)) // he's dead ! 586: { ! 587: tr = gi.trace (start, NULL, NULL, aim_good, self, MASK_SHOT); ! 588: if ((tr.ent != self->enemy) && (tr.ent != world)) { ! 589: if(g_showlogic && g_showlogic->value) ! 590: gi.dprintf ("infantry shot aborted due to bad target\n"); ! 591: return; ! 592: } ! 593: } ! 594: #endif ! 595: if (self->s.skinnum <= 1) ! 596: { ! 597: monster_fire_blaster (self, start, aim, 5, 600, flash_index, EF_BLASTER); ! 598: } ! 599: else if (self->s.skinnum <= 3) ! 600: { ! 601: monster_fire_shotgun (self, start, aim, 2, 1, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SHOTGUN_COUNT, flash_index); ! 602: } ! 603: else ! 604: { ! 605: // PMM - changed to wait from pausetime to not interfere with dodge code ! 606: if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME)) ! 607: self->wait = level.time + (3 + rand() % 8) * FRAMETIME; ! 608: ! 609: monster_fire_bullet (self, start, aim, 2, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_index); ! 610: ! 611: if (level.time >= self->wait) ! 612: self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; ! 613: else ! 614: self->monsterinfo.aiflags |= AI_HOLD_FRAME; ! 615: } ! 616: } ! 617: ! 618: // ATTACK1 (blaster/shotgun) ! 619: ! 620: void soldier_fire1 (edict_t *self) ! 621: { ! 622: soldier_fire (self, 0); ! 623: } ! 624: ! 625: void soldier_attack1_refire1 (edict_t *self) ! 626: { ! 627: // PMM - blindfire ! 628: if (self->monsterinfo.aiflags & AI_MANUAL_STEERING) ! 629: { ! 630: self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING; ! 631: return; ! 632: } ! 633: // pmm ! 634: ! 635: if (!self->enemy) ! 636: return; ! 637: ! 638: if (self->s.skinnum > 1) ! 639: return; ! 640: ! 641: if (self->enemy->health <= 0) ! 642: return; ! 643: ! 644: if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) ! 645: self->monsterinfo.nextframe = FRAME_attak102; ! 646: else ! 647: self->monsterinfo.nextframe = FRAME_attak110; ! 648: } ! 649: ! 650: void soldier_attack1_refire2 (edict_t *self) ! 651: { ! 652: if (!self->enemy) ! 653: return; ! 654: ! 655: if (self->s.skinnum < 2) ! 656: return; ! 657: ! 658: if (self->enemy->health <= 0) ! 659: return; ! 660: ! 661: if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) ! 662: self->monsterinfo.nextframe = FRAME_attak102; ! 663: } ! 664: ! 665: mframe_t soldier_frames_attack1 [] = ! 666: { ! 667: ai_charge, 0, NULL, ! 668: ai_charge, 0, NULL, ! 669: ai_charge, 0, soldier_fire1, ! 670: ai_charge, 0, NULL, ! 671: ai_charge, 0, NULL, ! 672: ai_charge, 0, soldier_attack1_refire1, ! 673: ai_charge, 0, NULL, ! 674: ai_charge, 0, soldier_cock, ! 675: ai_charge, 0, soldier_attack1_refire2, ! 676: ai_charge, 0, NULL, ! 677: ai_charge, 0, NULL, ! 678: ai_charge, 0, NULL ! 679: }; ! 680: mmove_t soldier_move_attack1 = {FRAME_attak101, FRAME_attak112, soldier_frames_attack1, soldier_run}; ! 681: ! 682: // ATTACK2 (blaster/shotgun) ! 683: ! 684: void soldier_fire2 (edict_t *self) ! 685: { ! 686: soldier_fire (self, 1); ! 687: } ! 688: ! 689: void soldier_attack2_refire1 (edict_t *self) ! 690: { ! 691: if (!self->enemy) ! 692: return; ! 693: ! 694: if (self->s.skinnum > 1) ! 695: return; ! 696: ! 697: if (self->enemy->health <= 0) ! 698: return; ! 699: ! 700: if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) ! 701: self->monsterinfo.nextframe = FRAME_attak204; ! 702: else ! 703: self->monsterinfo.nextframe = FRAME_attak216; ! 704: } ! 705: ! 706: void soldier_attack2_refire2 (edict_t *self) ! 707: { ! 708: if (!self->enemy) ! 709: return; ! 710: ! 711: if (self->s.skinnum < 2) ! 712: return; ! 713: ! 714: if (self->enemy->health <= 0) ! 715: return; ! 716: ! 717: if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) ! 718: self->monsterinfo.nextframe = FRAME_attak204; ! 719: } ! 720: ! 721: mframe_t soldier_frames_attack2 [] = ! 722: { ! 723: ai_charge, 0, NULL, ! 724: ai_charge, 0, NULL, ! 725: ai_charge, 0, NULL, ! 726: ai_charge, 0, NULL, ! 727: ai_charge, 0, soldier_fire2, ! 728: ai_charge, 0, NULL, ! 729: ai_charge, 0, NULL, ! 730: ai_charge, 0, soldier_attack2_refire1, ! 731: ai_charge, 0, NULL, ! 732: ai_charge, 0, NULL, ! 733: ai_charge, 0, NULL, ! 734: ai_charge, 0, NULL, ! 735: ai_charge, 0, soldier_cock, ! 736: ai_charge, 0, NULL, ! 737: ai_charge, 0, soldier_attack2_refire2, ! 738: ai_charge, 0, NULL, ! 739: ai_charge, 0, NULL, ! 740: ai_charge, 0, NULL ! 741: }; ! 742: mmove_t soldier_move_attack2 = {FRAME_attak201, FRAME_attak218, soldier_frames_attack2, soldier_run}; ! 743: ! 744: // ATTACK3 (duck and shoot) ! 745: /* ! 746: void soldier_duck_down (edict_t *self) ! 747: { ! 748: if ((g_showlogic) && (g_showlogic->value)) ! 749: gi.dprintf ("duck down - %d!\n", self->s.frame); ! 750: ! 751: self->monsterinfo.aiflags |= AI_DUCKED; ! 752: // self->maxs[2] -= 32; ! 753: self->maxs[2] = self->monsterinfo.base_height - 32; ! 754: self->takedamage = DAMAGE_YES; ! 755: if (self->monsterinfo.duck_wait_time < level.time) ! 756: { ! 757: if ((g_showlogic) && (g_showlogic->value)) ! 758: gi.dprintf ("soldier duck with no time!\n"); ! 759: self->monsterinfo.duck_wait_time = level.time + 1; ! 760: } ! 761: gi.linkentity (self); ! 762: } ! 763: ! 764: void soldier_duck_up (edict_t *self) ! 765: { ! 766: if ((g_showlogic) && (g_showlogic->value)) ! 767: gi.dprintf ("duck up - %d!\n", self->s.frame); ! 768: self->monsterinfo.aiflags &= ~AI_DUCKED; ! 769: // self->maxs[2] += 32; ! 770: self->maxs[2] = self->monsterinfo.base_height; ! 771: self->takedamage = DAMAGE_AIM; ! 772: gi.linkentity (self); ! 773: } ! 774: */ ! 775: void soldier_fire3 (edict_t *self) ! 776: { ! 777: monster_duck_down (self); ! 778: soldier_fire (self, 2); ! 779: } ! 780: ! 781: void soldier_attack3_refire (edict_t *self) ! 782: { ! 783: if ((level.time + 0.4) < self->monsterinfo.duck_wait_time) ! 784: self->monsterinfo.nextframe = FRAME_attak303; ! 785: } ! 786: ! 787: mframe_t soldier_frames_attack3 [] = ! 788: { ! 789: ai_charge, 0, NULL, ! 790: ai_charge, 0, NULL, ! 791: ai_charge, 0, soldier_fire3, ! 792: ai_charge, 0, NULL, ! 793: ai_charge, 0, NULL, ! 794: ai_charge, 0, soldier_attack3_refire, ! 795: ai_charge, 0, monster_duck_up, ! 796: ai_charge, 0, NULL, ! 797: ai_charge, 0, NULL ! 798: }; ! 799: mmove_t soldier_move_attack3 = {FRAME_attak301, FRAME_attak309, soldier_frames_attack3, soldier_run}; ! 800: ! 801: // ATTACK4 (machinegun) ! 802: ! 803: void soldier_fire4 (edict_t *self) ! 804: { ! 805: soldier_fire (self, 3); ! 806: // ! 807: // if (self->enemy->health <= 0) ! 808: // return; ! 809: // ! 810: // if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) ! 811: // self->monsterinfo.nextframe = FRAME_attak402; ! 812: } ! 813: ! 814: mframe_t soldier_frames_attack4 [] = ! 815: { ! 816: ai_charge, 0, NULL, ! 817: ai_charge, 0, NULL, ! 818: ai_charge, 0, soldier_fire4, ! 819: ai_charge, 0, NULL, ! 820: ai_charge, 0, NULL, ! 821: ai_charge, 0, NULL ! 822: }; ! 823: mmove_t soldier_move_attack4 = {FRAME_attak401, FRAME_attak406, soldier_frames_attack4, soldier_run}; ! 824: ! 825: #if 0 ! 826: // ATTACK5 (prone) ! 827: ! 828: void soldier_fire5 (edict_t *self) ! 829: { ! 830: soldier_fire (self, 4); ! 831: } ! 832: ! 833: void soldier_attack5_refire (edict_t *self) ! 834: { ! 835: if (!self->enemy) ! 836: return; ! 837: ! 838: if (self->enemy->health <= 0) ! 839: return; ! 840: ! 841: if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) ) ! 842: self->monsterinfo.nextframe = FRAME_attak505; ! 843: } ! 844: ! 845: mframe_t soldier_frames_attack5 [] = ! 846: { ! 847: ai_charge, 8, NULL, ! 848: ai_charge, 8, NULL, ! 849: ai_charge, 0, NULL, ! 850: ai_charge, 0, NULL, ! 851: ai_charge, 0, soldier_fire5, ! 852: ai_charge, 0, NULL, ! 853: ai_charge, 0, NULL, ! 854: ai_charge, 0, soldier_attack5_refire ! 855: }; ! 856: mmove_t soldier_move_attack5 = {FRAME_attak501, FRAME_attak508, soldier_frames_attack5, soldier_run}; ! 857: #endif ! 858: ! 859: // ATTACK6 (run & shoot) ! 860: ! 861: void soldier_fire8 (edict_t *self) ! 862: { ! 863: soldier_fire (self, -7); ! 864: // self->monsterinfo.aiflags |= AI_HOLD_FRAME; ! 865: // self->monsterinfo.pausetime = level.time + 1000000; ! 866: } ! 867: ! 868: void soldier_attack6_refire (edict_t *self) ! 869: { ! 870: // PMM - make sure dodge & charge bits are cleared ! 871: monster_done_dodge (self); ! 872: soldier_stop_charge (self); ! 873: ! 874: if (!self->enemy) ! 875: return; ! 876: ! 877: if (self->enemy->health <= 0) ! 878: return; ! 879: ! 880: // if (range(self, self->enemy) < RANGE_MID) ! 881: if (range(self, self->enemy) < RANGE_NEAR) ! 882: return; ! 883: ! 884: if ((skill->value == 3) || ((random() < (0.25*((float)skill->value))))) ! 885: self->monsterinfo.nextframe = FRAME_runs03; ! 886: } ! 887: ! 888: mframe_t soldier_frames_attack6 [] = ! 889: { ! 890: // PMM ! 891: // ai_run, 10, NULL, ! 892: ai_run, 10, soldier_start_charge, ! 893: ai_run, 4, NULL, ! 894: ai_run, 12, soldier_fire8, ! 895: ai_run, 11, NULL, ! 896: ai_run, 13, monster_done_dodge, ! 897: ai_run, 18, NULL, ! 898: ai_run, 15, NULL, ! 899: ai_run, 14, NULL, ! 900: ai_run, 11, NULL, ! 901: ai_run, 8, NULL, ! 902: ai_run, 11, NULL, ! 903: ai_run, 12, NULL, ! 904: ai_run, 12, NULL, ! 905: ai_run, 17, soldier_attack6_refire ! 906: }; ! 907: mmove_t soldier_move_attack6 = {FRAME_runs01, FRAME_runs14, soldier_frames_attack6, soldier_run}; ! 908: ! 909: void soldier_attack(edict_t *self) ! 910: { ! 911: float r, chance; ! 912: ! 913: monster_done_dodge (self); ! 914: ! 915: // PMM - blindfire! ! 916: if (self->monsterinfo.attack_state == AS_BLIND) ! 917: { ! 918: // setup shot probabilities ! 919: if (self->monsterinfo.blind_fire_delay < 1.0) ! 920: chance = 1.0; ! 921: else if (self->monsterinfo.blind_fire_delay < 7.5) ! 922: chance = 0.4; ! 923: else ! 924: chance = 0.1; ! 925: ! 926: r = random(); ! 927: ! 928: // gi.dprintf ("chance = %2.2f, roll = %2.2f\n", chance, r); ! 929: ! 930: // minimum of 2 seconds, plus 0-3, after the shots are done ! 931: self->monsterinfo.blind_fire_delay += 2.1 + 2.0 + random()*3.0; ! 932: ! 933: // don't shoot at the origin ! 934: if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin)) ! 935: return; ! 936: ! 937: // don't shoot if the dice say not to ! 938: if (r > chance) ! 939: { ! 940: // if ((g_showlogic) && (g_showlogic->value)) ! 941: // gi.dprintf ("blindfire - NO SHOT\n"); ! 942: return; ! 943: } ! 944: ! 945: // turn on manual steering to signal both manual steering and blindfire ! 946: self->monsterinfo.aiflags |= AI_MANUAL_STEERING; ! 947: self->monsterinfo.currentmove = &soldier_move_attack1; ! 948: self->monsterinfo.attack_finished = level.time + 1.5 + random(); ! 949: return; ! 950: } ! 951: // pmm ! 952: ! 953: // PMM - added this so the soldiers now run toward you and shoot instead of just stopping and shooting ! 954: // if ((range(self, self->enemy) >= RANGE_MID) && (r < (skill->value*0.25) && (self->s.skinnum <= 3))) ! 955: ! 956: r = random(); ! 957: ! 958: if ((!(self->monsterinfo.aiflags & AI_BLOCKED)) && (range(self, self->enemy) >= RANGE_NEAR) && (r < (skill->value*0.25) && (self->s.skinnum <= 3))) ! 959: { ! 960: self->monsterinfo.currentmove = &soldier_move_attack6; ! 961: } ! 962: else ! 963: { ! 964: if (self->s.skinnum < 4) ! 965: { ! 966: if (random() < 0.5) ! 967: self->monsterinfo.currentmove = &soldier_move_attack1; ! 968: else ! 969: self->monsterinfo.currentmove = &soldier_move_attack2; ! 970: } ! 971: else ! 972: { ! 973: self->monsterinfo.currentmove = &soldier_move_attack4; ! 974: } ! 975: } ! 976: } ! 977: ! 978: ! 979: // ! 980: // SIGHT ! 981: // ! 982: ! 983: void soldier_sight(edict_t *self, edict_t *other) ! 984: { ! 985: if (random() < 0.5) ! 986: gi.sound (self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0); ! 987: else ! 988: gi.sound (self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0); ! 989: ! 990: // if ((skill->value > 0) && (self->enemy) && (range(self, self->enemy) >= RANGE_MID)) ! 991: if ((skill->value > 0) && (self->enemy) && (range(self, self->enemy) >= RANGE_NEAR)) ! 992: { ! 993: // PMM - don't let machinegunners run & shoot ! 994: if ((random() > 0.75) && (self->s.skinnum <= 3)) ! 995: self->monsterinfo.currentmove = &soldier_move_attack6; ! 996: } ! 997: } ! 998: ! 999: // ! 1000: // DUCK ! 1001: // ! 1002: /* ! 1003: void soldier_duck_hold (edict_t *self) ! 1004: { ! 1005: if (level.time >= self->monsterinfo.duck_wait_time) ! 1006: self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; ! 1007: else ! 1008: self->monsterinfo.aiflags |= AI_HOLD_FRAME; ! 1009: } ! 1010: */ ! 1011: mframe_t soldier_frames_duck [] = ! 1012: { ! 1013: ai_move, 5, monster_duck_down, ! 1014: ai_move, -1, monster_duck_hold, ! 1015: ai_move, 1, NULL, ! 1016: ai_move, 0, monster_duck_up, ! 1017: ai_move, 5, NULL ! 1018: }; ! 1019: mmove_t soldier_move_duck = {FRAME_duck01, FRAME_duck05, soldier_frames_duck, soldier_run}; ! 1020: ! 1021: /* ! 1022: void soldier_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr) ! 1023: { ! 1024: //=========== ! 1025: //PMM - rogue rewrite of dodge code. ! 1026: // lots o' changes in here. Basically, they now check the tr and see if ducking would help, ! 1027: // and if it doesn't, they dodge like mad ! 1028: float r = random(); ! 1029: float height; ! 1030: ! 1031: if ((g_showlogic) && (g_showlogic->value)) ! 1032: { ! 1033: if (self->monsterinfo.aiflags & AI_DODGING) ! 1034: gi.dprintf ("dodging - "); ! 1035: if (self->monsterinfo.aiflags & AI_DUCKED) ! 1036: gi.dprintf ("ducked - "); ! 1037: } ! 1038: if (!self->enemy) ! 1039: { ! 1040: self->enemy = attacker; ! 1041: FoundTarget (self); ! 1042: } ! 1043: ! 1044: // PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was ! 1045: // seeing numbers like 13 and 14) ! 1046: if ((eta < 0.1) || (eta > 5)) ! 1047: { ! 1048: if ((g_showlogic) && (g_showlogic->value)) ! 1049: gi.dprintf ("timeout\n"); ! 1050: return; ! 1051: } ! 1052: ! 1053: // skill level determination.. ! 1054: if (r > (0.25*((skill->value)+1))) ! 1055: { ! 1056: if ((g_showlogic) && (g_showlogic->value)) ! 1057: gi.dprintf ("skillout\n"); ! 1058: return; ! 1059: } ! 1060: ! 1061: // stop charging, since we're going to dodge (somehow) instead ! 1062: soldier_stop_charge (self); ! 1063: ! 1064: height = self->absmax[2]-32-1; // the -1 is because the absmax is s.origin + maxs + 1 ! 1065: ! 1066: // if we're ducking already, or the shot is at our knees ! 1067: if ((tr->endpos[2] <= height) || (self->monsterinfo.aiflags & AI_DUCKED)) ! 1068: { ! 1069: vec3_t right, diff; ! 1070: ! 1071: // if we're already dodging, just finish the sequence, i.e. don't do anything else ! 1072: if (self->monsterinfo.aiflags & AI_DODGING) ! 1073: { ! 1074: if ((g_showlogic) && (g_showlogic->value)) ! 1075: gi.dprintf ("already dodging\n"); ! 1076: return; ! 1077: } ! 1078: ! 1079: AngleVectors (self->s.angles, NULL, right, NULL); ! 1080: VectorSubtract (tr->endpos, self->s.origin, diff); ! 1081: ! 1082: if (DotProduct (right, diff) < 0) ! 1083: { ! 1084: self->monsterinfo.lefty = 1; ! 1085: // gi.dprintf ("left\n"); ! 1086: } else { ! 1087: // gi.dprintf ("right\n"); ! 1088: } ! 1089: // if it doesn't sense to duck, try to strafe and shoot ! 1090: // we don't want the machine gun guys running & shooting (looks bad) ! 1091: ! 1092: // if we are currently ducked, unduck ! 1093: if (self->monsterinfo.aiflags & AI_DUCKED) ! 1094: { ! 1095: if ((g_showlogic) && (g_showlogic->value)) ! 1096: gi.dprintf ("unducking - "); ! 1097: soldier_duck_up(self); ! 1098: } ! 1099: ! 1100: self->monsterinfo.aiflags |= AI_DODGING; ! 1101: self->monsterinfo.attack_state = AS_SLIDING; ! 1102: ! 1103: if (self->s.skinnum <= 3) ! 1104: { ! 1105: if ((g_showlogic) && (g_showlogic->value)) ! 1106: gi.dprintf ("shooting back!\n"); ! 1107: self->monsterinfo.currentmove = &soldier_move_attack6; ! 1108: } ! 1109: else ! 1110: { ! 1111: if ((g_showlogic) && (g_showlogic->value)) ! 1112: gi.dprintf ("strafing away!\n"); ! 1113: self->monsterinfo.currentmove = &soldier_move_start_run; ! 1114: } ! 1115: return; ! 1116: } ! 1117: ! 1118: // if we're here, we're ducking, so clear the dodge bit if it's set ! 1119: ! 1120: if ((g_showlogic) && (g_showlogic->value)) ! 1121: gi.dprintf ("ducking!\n"); ! 1122: if (skill->value == 0) ! 1123: { ! 1124: // set this prematurely; it doesn't hurt, and prevents extra iterations ! 1125: self->monsterinfo.aiflags |= AI_DUCKED; ! 1126: monster_done_dodge (self); ! 1127: self->monsterinfo.currentmove = &soldier_move_duck; ! 1128: // PMM - stupid dodge ! 1129: self->monsterinfo.duck_wait_time = level.time + eta + 1; ! 1130: return; ! 1131: } ! 1132: // PMM - since we're only ducking some of the time, this needs to be moved down below ! 1133: // self->monsterinfo.duck_wait_time = level.time + eta + 0.3; ! 1134: ! 1135: r = random(); ! 1136: ! 1137: // set this prematurely; it doesn't hurt, and prevents extra iterations ! 1138: self->monsterinfo.aiflags |= AI_DUCKED; ! 1139: monster_done_dodge (self); ! 1140: ! 1141: if (r > (skill->value * 0.33)) ! 1142: { ! 1143: self->monsterinfo.currentmove = &soldier_move_duck; ! 1144: self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value)); ! 1145: // has to be done immediately otherwise he can get stuck ! 1146: soldier_duck_down(self); ! 1147: } ! 1148: else ! 1149: { ! 1150: // has to be done immediately otherwise he can get stuck ! 1151: soldier_duck_down(self); ! 1152: self->monsterinfo.duck_wait_time = level.time + eta + 1; ! 1153: self->monsterinfo.currentmove = &soldier_move_attack3; ! 1154: self->monsterinfo.nextframe = FRAME_attak301; ! 1155: } ! 1156: return; ! 1157: //PMM ! 1158: //=========== ! 1159: ! 1160: } ! 1161: */ ! 1162: // pmm - blocking code ! 1163: ! 1164: qboolean soldier_blocked (edict_t *self, float dist) ! 1165: { ! 1166: // don't do anything if you're dodging ! 1167: if ((self->monsterinfo.aiflags & AI_DODGING) || (self->monsterinfo.aiflags & AI_DUCKED)) ! 1168: return false; ! 1169: ! 1170: if(blocked_checkshot (self, 0.25 + (0.05 * skill->value) )) ! 1171: return true; ! 1172: ! 1173: // if(blocked_checkjump (self, dist, 192, 40)) ! 1174: // { ! 1175: // soldier_jump(self); ! 1176: // return true; ! 1177: // } ! 1178: ! 1179: if(blocked_checkplat (self, dist)) ! 1180: return true; ! 1181: ! 1182: return false; ! 1183: } ! 1184: ! 1185: // ! 1186: // DEATH ! 1187: // ! 1188: ! 1189: void soldier_fire6 (edict_t *self) ! 1190: { ! 1191: soldier_fire (self, 5); ! 1192: } ! 1193: ! 1194: void soldier_fire7 (edict_t *self) ! 1195: { ! 1196: soldier_fire (self, 6); ! 1197: } ! 1198: ! 1199: void soldier_dead (edict_t *self) ! 1200: { ! 1201: VectorSet (self->mins, -16, -16, -24); ! 1202: VectorSet (self->maxs, 16, 16, -8); ! 1203: self->movetype = MOVETYPE_TOSS; ! 1204: self->svflags |= SVF_DEADMONSTER; ! 1205: self->nextthink = 0; ! 1206: gi.linkentity (self); ! 1207: } ! 1208: ! 1209: // pmm - this quickie does a location trace to try to grow the bounding box ! 1210: // ! 1211: // this is because the frames are off; the origin is at the guy's feet. ! 1212: void soldier_dead2 (edict_t *self) ! 1213: { ! 1214: vec3_t tempmins, tempmaxs, temporg; ! 1215: trace_t tr; ! 1216: ! 1217: VectorCopy (self->s.origin, temporg); ! 1218: // this is because location traces done at the floor are guaranteed to hit the floor ! 1219: // (inside the sv_trace code it grows the bbox by 1 in all directions) ! 1220: temporg[2] += 1; ! 1221: ! 1222: VectorSet (tempmins, -32, -32, -24); ! 1223: VectorSet (tempmaxs, 32, 32, -8); ! 1224: ! 1225: tr = gi.trace (temporg, tempmins, tempmaxs, temporg, self, MASK_SOLID); ! 1226: if (tr.startsolid || tr.allsolid) ! 1227: { ! 1228: VectorSet (self->mins, -16, -16, -24); ! 1229: VectorSet (self->maxs, 16, 16, -8); ! 1230: } ! 1231: else ! 1232: { ! 1233: VectorCopy (tempmins, self->mins); ! 1234: VectorCopy (tempmaxs, self->maxs); ! 1235: } ! 1236: self->movetype = MOVETYPE_TOSS; ! 1237: self->svflags |= SVF_DEADMONSTER; ! 1238: self->nextthink = 0; ! 1239: gi.linkentity (self); ! 1240: } ! 1241: ! 1242: mframe_t soldier_frames_death1 [] = ! 1243: { ! 1244: ai_move, 0, NULL, ! 1245: ai_move, -10, NULL, ! 1246: ai_move, -10, NULL, ! 1247: ai_move, -10, NULL, ! 1248: ai_move, -5, NULL, ! 1249: ai_move, 0, NULL, ! 1250: ai_move, 0, NULL, ! 1251: ai_move, 0, NULL, ! 1252: ai_move, 0, NULL, ! 1253: ai_move, 0, NULL, ! 1254: ! 1255: ai_move, 0, NULL, ! 1256: ai_move, 0, NULL, ! 1257: ai_move, 0, NULL, ! 1258: ai_move, 0, NULL, ! 1259: ai_move, 0, NULL, ! 1260: ai_move, 0, NULL, ! 1261: ai_move, 0, NULL, ! 1262: ai_move, 0, NULL, ! 1263: ai_move, 0, NULL, ! 1264: ai_move, 0, NULL, ! 1265: ! 1266: ai_move, 0, NULL, ! 1267: ai_move, 0, soldier_fire6, ! 1268: ai_move, 0, NULL, ! 1269: ai_move, 0, NULL, ! 1270: ai_move, 0, soldier_fire7, ! 1271: ai_move, 0, NULL, ! 1272: ai_move, 0, NULL, ! 1273: ai_move, 0, NULL, ! 1274: ai_move, 0, NULL, ! 1275: ai_move, 0, NULL, ! 1276: ! 1277: ai_move, 0, NULL, ! 1278: ai_move, 0, NULL, ! 1279: ai_move, 0, NULL, ! 1280: ai_move, 0, NULL, ! 1281: ai_move, 0, NULL, ! 1282: ai_move, 0, NULL ! 1283: }; ! 1284: mmove_t soldier_move_death1 = {FRAME_death101, FRAME_death136, soldier_frames_death1, soldier_dead}; ! 1285: ! 1286: mframe_t soldier_frames_death2 [] = ! 1287: { ! 1288: ai_move, -5, NULL, ! 1289: ai_move, -5, NULL, ! 1290: ai_move, -5, NULL, ! 1291: ai_move, 0, NULL, ! 1292: ai_move, 0, NULL, ! 1293: ai_move, 0, NULL, ! 1294: ai_move, 0, NULL, ! 1295: ai_move, 0, NULL, ! 1296: ai_move, 0, NULL, ! 1297: ai_move, 0, NULL, ! 1298: ! 1299: ai_move, 0, NULL, ! 1300: ai_move, 0, NULL, ! 1301: ai_move, 0, NULL, ! 1302: ai_move, 0, NULL, ! 1303: ai_move, 0, NULL, ! 1304: ai_move, 0, NULL, ! 1305: ai_move, 0, NULL, ! 1306: ai_move, 0, NULL, ! 1307: ai_move, 0, NULL, ! 1308: ai_move, 0, NULL, ! 1309: ! 1310: ai_move, 0, NULL, ! 1311: ai_move, 0, NULL, ! 1312: ai_move, 0, NULL, ! 1313: ai_move, 0, NULL, ! 1314: ai_move, 0, NULL, ! 1315: ai_move, 0, NULL, ! 1316: ai_move, 0, NULL, ! 1317: ai_move, 0, NULL, ! 1318: ai_move, 0, NULL, ! 1319: ai_move, 0, NULL, ! 1320: ! 1321: ai_move, 0, NULL, ! 1322: ai_move, 0, NULL, ! 1323: ai_move, 0, NULL, ! 1324: ai_move, 0, NULL, ! 1325: ai_move, 0, NULL ! 1326: }; ! 1327: mmove_t soldier_move_death2 = {FRAME_death201, FRAME_death235, soldier_frames_death2, soldier_dead}; ! 1328: ! 1329: mframe_t soldier_frames_death3 [] = ! 1330: { ! 1331: ai_move, -5, NULL, ! 1332: ai_move, -5, NULL, ! 1333: ai_move, -5, NULL, ! 1334: ai_move, 0, NULL, ! 1335: ai_move, 0, NULL, ! 1336: ai_move, 0, NULL, ! 1337: ai_move, 0, NULL, ! 1338: ai_move, 0, NULL, ! 1339: ai_move, 0, NULL, ! 1340: ai_move, 0, NULL, ! 1341: ! 1342: ai_move, 0, NULL, ! 1343: ai_move, 0, NULL, ! 1344: ai_move, 0, NULL, ! 1345: ai_move, 0, NULL, ! 1346: ai_move, 0, NULL, ! 1347: ai_move, 0, NULL, ! 1348: ai_move, 0, NULL, ! 1349: ai_move, 0, NULL, ! 1350: ai_move, 0, NULL, ! 1351: ai_move, 0, NULL, ! 1352: ! 1353: ai_move, 0, NULL, ! 1354: ai_move, 0, NULL, ! 1355: ai_move, 0, NULL, ! 1356: ai_move, 0, NULL, ! 1357: ai_move, 0, NULL, ! 1358: ai_move, 0, NULL, ! 1359: ai_move, 0, NULL, ! 1360: ai_move, 0, NULL, ! 1361: ai_move, 0, NULL, ! 1362: ai_move, 0, NULL, ! 1363: ! 1364: ai_move, 0, NULL, ! 1365: ai_move, 0, NULL, ! 1366: ai_move, 0, NULL, ! 1367: ai_move, 0, NULL, ! 1368: ai_move, 0, NULL, ! 1369: ai_move, 0, NULL, ! 1370: ai_move, 0, NULL, ! 1371: ai_move, 0, NULL, ! 1372: ai_move, 0, NULL, ! 1373: ai_move, 0, NULL, ! 1374: ! 1375: ai_move, 0, NULL, ! 1376: ai_move, 0, NULL, ! 1377: ai_move, 0, NULL, ! 1378: ai_move, 0, NULL, ! 1379: ai_move, 0, NULL, ! 1380: }; ! 1381: mmove_t soldier_move_death3 = {FRAME_death301, FRAME_death345, soldier_frames_death3, soldier_dead}; ! 1382: ! 1383: mframe_t soldier_frames_death4 [] = ! 1384: { ! 1385: ai_move, 0, NULL, ! 1386: ai_move, 0, NULL, ! 1387: ai_move, 0, NULL, ! 1388: ai_move, 0, NULL, ! 1389: ai_move, 0, NULL, ! 1390: ai_move, 0, NULL, ! 1391: ai_move, 0, NULL, ! 1392: ai_move, 0, NULL, ! 1393: ai_move, 0, NULL, ! 1394: ai_move, 0, NULL, ! 1395: ! 1396: ai_move, 0, NULL, ! 1397: ai_move, 0, NULL, ! 1398: ai_move, 0, NULL, ! 1399: ai_move, 0, NULL, ! 1400: ai_move, 0, NULL, ! 1401: ai_move, 0, NULL, ! 1402: ai_move, 0, NULL, ! 1403: ai_move, 0, NULL, ! 1404: ai_move, 0, NULL, ! 1405: ai_move, 0, NULL, ! 1406: ! 1407: ai_move, 0, NULL, ! 1408: ai_move, 0, NULL, ! 1409: ai_move, 0, NULL, ! 1410: ai_move, 0, NULL, ! 1411: ai_move, 0, NULL, ! 1412: ai_move, 0, NULL, ! 1413: ai_move, 0, NULL, ! 1414: ai_move, 0, NULL, ! 1415: ai_move, 0, NULL, ! 1416: ai_move, 0, NULL, ! 1417: ! 1418: ai_move, 0, NULL, ! 1419: ai_move, 0, NULL, ! 1420: ai_move, 0, NULL, ! 1421: ai_move, 0, NULL, ! 1422: ai_move, 0, NULL, ! 1423: ai_move, 0, NULL, ! 1424: ai_move, 0, NULL, ! 1425: ai_move, 0, NULL, ! 1426: ai_move, 0, NULL, ! 1427: ai_move, 0, NULL, ! 1428: ! 1429: ai_move, 0, NULL, ! 1430: ai_move, 0, NULL, ! 1431: ai_move, 0, NULL, ! 1432: ai_move, 0, NULL, ! 1433: ai_move, 0, NULL, ! 1434: ai_move, 0, NULL, ! 1435: ai_move, 0, NULL, ! 1436: ai_move, 0, NULL, ! 1437: ai_move, 0, NULL, ! 1438: ai_move, 0, NULL, ! 1439: ! 1440: ai_move, 0, NULL, ! 1441: ai_move, 0, NULL, ! 1442: ai_move, 0, NULL ! 1443: }; ! 1444: // PMM -changed to soldier_dead2 to get a larger bounding box ! 1445: mmove_t soldier_move_death4 = {FRAME_death401, FRAME_death453, soldier_frames_death4, soldier_dead2}; ! 1446: ! 1447: mframe_t soldier_frames_death5 [] = ! 1448: { ! 1449: ai_move, -5, NULL, ! 1450: ai_move, -5, NULL, ! 1451: ai_move, -5, NULL, ! 1452: ai_move, 0, NULL, ! 1453: ai_move, 0, NULL, ! 1454: ai_move, 0, NULL, ! 1455: ai_move, 0, NULL, ! 1456: ai_move, 0, NULL, ! 1457: ai_move, 0, NULL, ! 1458: ai_move, 0, NULL, ! 1459: ! 1460: ai_move, 0, NULL, ! 1461: ai_move, 0, NULL, ! 1462: ai_move, 0, NULL, ! 1463: ai_move, 0, NULL, ! 1464: ai_move, 0, NULL, ! 1465: ai_move, 0, NULL, ! 1466: ai_move, 0, NULL, ! 1467: ai_move, 0, NULL, ! 1468: ai_move, 0, NULL, ! 1469: ai_move, 0, NULL, ! 1470: ! 1471: ai_move, 0, NULL, ! 1472: ai_move, 0, NULL, ! 1473: ai_move, 0, NULL, ! 1474: ai_move, 0, NULL ! 1475: }; ! 1476: mmove_t soldier_move_death5 = {FRAME_death501, FRAME_death524, soldier_frames_death5, soldier_dead}; ! 1477: ! 1478: mframe_t soldier_frames_death6 [] = ! 1479: { ! 1480: ai_move, 0, NULL, ! 1481: ai_move, 0, NULL, ! 1482: ai_move, 0, NULL, ! 1483: ai_move, 0, NULL, ! 1484: ai_move, 0, NULL, ! 1485: ai_move, 0, NULL, ! 1486: ai_move, 0, NULL, ! 1487: ai_move, 0, NULL, ! 1488: ai_move, 0, NULL, ! 1489: ai_move, 0, NULL ! 1490: }; ! 1491: mmove_t soldier_move_death6 = {FRAME_death601, FRAME_death610, soldier_frames_death6, soldier_dead}; ! 1492: ! 1493: void soldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 1494: { ! 1495: int n; ! 1496: ! 1497: // check for gib ! 1498: if (self->health <= self->gib_health) ! 1499: { ! 1500: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); ! 1501: for (n= 0; n < 3; n++) ! 1502: ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); ! 1503: ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC); ! 1504: ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); ! 1505: self->deadflag = DEAD_DEAD; ! 1506: return; ! 1507: } ! 1508: ! 1509: if (self->deadflag == DEAD_DEAD) ! 1510: return; ! 1511: ! 1512: // regular death ! 1513: self->deadflag = DEAD_DEAD; ! 1514: self->takedamage = DAMAGE_YES; ! 1515: self->s.skinnum |= 1; ! 1516: ! 1517: if (self->s.skinnum == 1) ! 1518: gi.sound (self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0); ! 1519: else if (self->s.skinnum == 3) ! 1520: gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0); ! 1521: else // (self->s.skinnum == 5) ! 1522: gi.sound (self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0); ! 1523: ! 1524: if (fabs((self->s.origin[2] + self->viewheight) - point[2]) <= 4) ! 1525: { ! 1526: // head shot ! 1527: self->monsterinfo.currentmove = &soldier_move_death3; ! 1528: return; ! 1529: } ! 1530: ! 1531: n = rand() % 5; ! 1532: if (n == 0) ! 1533: self->monsterinfo.currentmove = &soldier_move_death1; ! 1534: else if (n == 1) ! 1535: self->monsterinfo.currentmove = &soldier_move_death2; ! 1536: else if (n == 2) ! 1537: self->monsterinfo.currentmove = &soldier_move_death4; ! 1538: else if (n == 3) ! 1539: self->monsterinfo.currentmove = &soldier_move_death5; ! 1540: else ! 1541: self->monsterinfo.currentmove = &soldier_move_death6; ! 1542: } ! 1543: ! 1544: // ! 1545: // NEW DODGE CODE ! 1546: // ! 1547: ! 1548: void soldier_sidestep (edict_t *self) ! 1549: { ! 1550: if (self->s.skinnum <= 3) ! 1551: { ! 1552: if ((g_showlogic) && (g_showlogic->value)) ! 1553: gi.dprintf ("shooting back!\n"); ! 1554: if (self->monsterinfo.currentmove != &soldier_move_attack6) ! 1555: self->monsterinfo.currentmove = &soldier_move_attack6; ! 1556: } ! 1557: else ! 1558: { ! 1559: if ((g_showlogic) && (g_showlogic->value)) ! 1560: gi.dprintf ("strafing away!\n"); ! 1561: if (self->monsterinfo.currentmove != &soldier_move_start_run) ! 1562: self->monsterinfo.currentmove = &soldier_move_start_run; ! 1563: } ! 1564: } ! 1565: ! 1566: void soldier_duck (edict_t *self, float eta) ! 1567: { ! 1568: float r; ! 1569: ! 1570: // has to be done immediately otherwise he can get stuck ! 1571: monster_duck_down(self); ! 1572: ! 1573: if (skill->value == 0) ! 1574: { ! 1575: // PMM - stupid dodge ! 1576: self->monsterinfo.nextframe = FRAME_duck01; ! 1577: self->monsterinfo.currentmove = &soldier_move_duck; ! 1578: self->monsterinfo.duck_wait_time = level.time + eta + 1; ! 1579: return; ! 1580: } ! 1581: ! 1582: r = random(); ! 1583: ! 1584: if (r > (skill->value * 0.3)) ! 1585: { ! 1586: self->monsterinfo.nextframe = FRAME_duck01; ! 1587: self->monsterinfo.currentmove = &soldier_move_duck; ! 1588: self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value)); ! 1589: } ! 1590: else ! 1591: { ! 1592: self->monsterinfo.nextframe = FRAME_attak301; ! 1593: self->monsterinfo.currentmove = &soldier_move_attack3; ! 1594: self->monsterinfo.duck_wait_time = level.time + eta + 1; ! 1595: } ! 1596: return; ! 1597: } ! 1598: ! 1599: //========= ! 1600: //ROGUE ! 1601: void soldier_blind (edict_t *self); ! 1602: ! 1603: mframe_t soldier_frames_blind [] = ! 1604: { ! 1605: ai_move, 0, soldier_idle, ! 1606: ai_move, 0, NULL, ! 1607: ai_move, 0, NULL, ! 1608: ai_move, 0, NULL, ! 1609: ai_move, 0, NULL, ! 1610: ai_move, 0, NULL, ! 1611: ai_move, 0, NULL, ! 1612: ai_move, 0, NULL, ! 1613: ai_move, 0, NULL, ! 1614: ai_move, 0, NULL, ! 1615: ! 1616: ai_move, 0, NULL, ! 1617: ai_move, 0, NULL, ! 1618: ai_move, 0, NULL, ! 1619: ai_move, 0, NULL, ! 1620: ai_move, 0, NULL, ! 1621: ai_move, 0, NULL, ! 1622: ai_move, 0, NULL, ! 1623: ai_move, 0, NULL, ! 1624: ai_move, 0, NULL, ! 1625: ai_move, 0, NULL, ! 1626: ! 1627: ai_move, 0, NULL, ! 1628: ai_move, 0, NULL, ! 1629: ai_move, 0, NULL, ! 1630: ai_move, 0, NULL, ! 1631: ai_move, 0, NULL, ! 1632: ai_move, 0, NULL, ! 1633: ai_move, 0, NULL, ! 1634: ai_move, 0, NULL, ! 1635: ai_move, 0, NULL, ! 1636: ai_move, 0, NULL ! 1637: }; ! 1638: mmove_t soldier_move_blind = {FRAME_stand101, FRAME_stand130, soldier_frames_blind, soldier_blind}; ! 1639: ! 1640: void soldier_blind (edict_t *self) ! 1641: { ! 1642: self->monsterinfo.currentmove = &soldier_move_blind; ! 1643: } ! 1644: //ROGUE ! 1645: //========= ! 1646: ! 1647: // ! 1648: // SPAWN ! 1649: // ! 1650: ! 1651: void SP_monster_soldier_x (edict_t *self) ! 1652: { ! 1653: ! 1654: self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2"); ! 1655: //PMM ! 1656: // self->s.effects |= EF_SPLATTER; ! 1657: //PMM ! 1658: self->monsterinfo.scale = MODEL_SCALE; ! 1659: VectorSet (self->mins, -16, -16, -24); ! 1660: VectorSet (self->maxs, 16, 16, 32); ! 1661: self->movetype = MOVETYPE_STEP; ! 1662: self->solid = SOLID_BBOX; ! 1663: ! 1664: sound_idle = gi.soundindex ("soldier/solidle1.wav"); ! 1665: sound_sight1 = gi.soundindex ("soldier/solsght1.wav"); ! 1666: sound_sight2 = gi.soundindex ("soldier/solsrch1.wav"); ! 1667: sound_cock = gi.soundindex ("infantry/infatck3.wav"); ! 1668: ! 1669: self->mass = 100; ! 1670: ! 1671: self->pain = soldier_pain; ! 1672: self->die = soldier_die; ! 1673: ! 1674: self->monsterinfo.stand = soldier_stand; ! 1675: self->monsterinfo.walk = soldier_walk; ! 1676: self->monsterinfo.run = soldier_run; ! 1677: self->monsterinfo.dodge = M_MonsterDodge; ! 1678: self->monsterinfo.attack = soldier_attack; ! 1679: self->monsterinfo.melee = NULL; ! 1680: self->monsterinfo.sight = soldier_sight; ! 1681: ! 1682: //===== ! 1683: //ROGUE ! 1684: self->monsterinfo.blocked = soldier_blocked; ! 1685: self->monsterinfo.duck = soldier_duck; ! 1686: self->monsterinfo.unduck = monster_duck_up; ! 1687: self->monsterinfo.sidestep = soldier_sidestep; ! 1688: ! 1689: if(self->spawnflags & 8) // blind ! 1690: self->monsterinfo.stand = soldier_blind; ! 1691: //ROGUE ! 1692: //===== ! 1693: ! 1694: gi.linkentity (self); ! 1695: ! 1696: self->monsterinfo.stand (self); ! 1697: ! 1698: walkmonster_start (self); ! 1699: } ! 1700: ! 1701: ! 1702: /*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight Blind ! 1703: ! 1704: Blind - monster will just stand there until triggered ! 1705: */ ! 1706: void SP_monster_soldier_light (edict_t *self) ! 1707: { ! 1708: if (deathmatch->value) ! 1709: { ! 1710: G_FreeEdict (self); ! 1711: return; ! 1712: } ! 1713: ! 1714: SP_monster_soldier_x (self); ! 1715: ! 1716: sound_pain_light = gi.soundindex ("soldier/solpain2.wav"); ! 1717: sound_death_light = gi.soundindex ("soldier/soldeth2.wav"); ! 1718: gi.modelindex ("models/objects/laser/tris.md2"); ! 1719: gi.soundindex ("misc/lasfly.wav"); ! 1720: gi.soundindex ("soldier/solatck2.wav"); ! 1721: ! 1722: self->s.skinnum = 0; ! 1723: self->health = 20; ! 1724: self->gib_health = -30; ! 1725: ! 1726: // PMM - blindfire ! 1727: self->monsterinfo.blindfire = true; ! 1728: } ! 1729: ! 1730: /*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight Blind ! 1731: ! 1732: Blind - monster will just stand there until triggered ! 1733: */ ! 1734: void SP_monster_soldier (edict_t *self) ! 1735: { ! 1736: if (deathmatch->value) ! 1737: { ! 1738: G_FreeEdict (self); ! 1739: return; ! 1740: } ! 1741: ! 1742: SP_monster_soldier_x (self); ! 1743: ! 1744: sound_pain = gi.soundindex ("soldier/solpain1.wav"); ! 1745: sound_death = gi.soundindex ("soldier/soldeth1.wav"); ! 1746: gi.soundindex ("soldier/solatck1.wav"); ! 1747: ! 1748: self->s.skinnum = 2; ! 1749: self->health = 30; ! 1750: self->gib_health = -30; ! 1751: } ! 1752: ! 1753: /*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight Blind ! 1754: ! 1755: Blind - monster will just stand there until triggered ! 1756: */ ! 1757: void SP_monster_soldier_ss (edict_t *self) ! 1758: { ! 1759: if (deathmatch->value) ! 1760: { ! 1761: G_FreeEdict (self); ! 1762: return; ! 1763: } ! 1764: ! 1765: SP_monster_soldier_x (self); ! 1766: ! 1767: sound_pain_ss = gi.soundindex ("soldier/solpain3.wav"); ! 1768: sound_death_ss = gi.soundindex ("soldier/soldeth3.wav"); ! 1769: gi.soundindex ("soldier/solatck3.wav"); ! 1770: ! 1771: self->s.skinnum = 4; ! 1772: self->health = 40; ! 1773: self->gib_health = -30; ! 1774: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.