|
|
1.1 root 1: /* 1.1.1.2 ! root 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: /* 1.1 root 21: ============================================================================== 22: 23: GUNNER 24: 25: ============================================================================== 26: */ 27: 28: #include "g_local.h" 29: #include "m_gunner.h" 30: 31: 32: static int sound_pain; 33: static int sound_pain2; 34: static int sound_death; 35: static int sound_idle; 36: static int sound_open; 37: static int sound_search; 38: static int sound_sight; 39: 40: 41: void gunner_idlesound (edict_t *self) 42: { 43: gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0); 44: } 45: 46: void gunner_sight (edict_t *self, edict_t *other) 47: { 48: gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); 49: } 50: 51: void gunner_search (edict_t *self) 52: { 53: gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0); 54: } 55: 56: 57: qboolean visible (edict_t *self, edict_t *other); 58: void GunnerGrenade (edict_t *self); 59: void GunnerFire (edict_t *self); 60: void gunner_fire_chain(edict_t *self); 61: void gunner_refire_chain(edict_t *self); 62: 63: 64: void gunner_stand (edict_t *self); 65: 66: mframe_t gunner_frames_fidget [] = 67: { 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: ai_stand, 0, gunner_idlesound, 76: ai_stand, 0, NULL, 77: 78: ai_stand, 0, NULL, 79: ai_stand, 0, NULL, 80: ai_stand, 0, NULL, 81: ai_stand, 0, NULL, 82: ai_stand, 0, NULL, 83: ai_stand, 0, NULL, 84: ai_stand, 0, NULL, 85: ai_stand, 0, NULL, 86: ai_stand, 0, NULL, 87: ai_stand, 0, NULL, 88: 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: ai_stand, 0, NULL, 98: ai_stand, 0, NULL, 99: 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: ai_stand, 0, NULL, 109: ai_stand, 0, NULL, 110: 111: ai_stand, 0, NULL, 112: ai_stand, 0, NULL, 113: ai_stand, 0, NULL, 114: ai_stand, 0, NULL, 115: ai_stand, 0, NULL, 116: ai_stand, 0, NULL, 117: ai_stand, 0, NULL, 118: ai_stand, 0, NULL, 119: ai_stand, 0, NULL, 120: ai_stand, 0, NULL 121: }; 122: mmove_t gunner_move_fidget = {FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand}; 123: 124: void gunner_fidget (edict_t *self) 125: { 126: if (self->monsterinfo.aiflags & AI_STAND_GROUND) 127: return; 128: if (random() <= 0.05) 129: self->monsterinfo.currentmove = &gunner_move_fidget; 130: } 131: 132: mframe_t gunner_frames_stand [] = 133: { 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: ai_stand, 0, NULL, 141: ai_stand, 0, NULL, 142: ai_stand, 0, NULL, 143: ai_stand, 0, gunner_fidget, 144: 145: ai_stand, 0, NULL, 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, gunner_fidget, 155: 156: ai_stand, 0, NULL, 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, gunner_fidget 166: }; 167: mmove_t gunner_move_stand = {FRAME_stand01, FRAME_stand30, gunner_frames_stand, NULL}; 168: 169: void gunner_stand (edict_t *self) 170: { 171: self->monsterinfo.currentmove = &gunner_move_stand; 172: } 173: 174: 175: mframe_t gunner_frames_walk [] = 176: { 177: ai_walk, 0, NULL, 178: ai_walk, 3, NULL, 179: ai_walk, 4, NULL, 180: ai_walk, 5, NULL, 181: ai_walk, 7, NULL, 182: ai_walk, 2, NULL, 183: ai_walk, 6, NULL, 184: ai_walk, 4, NULL, 185: ai_walk, 2, NULL, 186: ai_walk, 7, NULL, 187: ai_walk, 5, NULL, 188: ai_walk, 7, NULL, 189: ai_walk, 4, NULL 190: }; 191: mmove_t gunner_move_walk = {FRAME_walk07, FRAME_walk19, gunner_frames_walk, NULL}; 192: 193: void gunner_walk (edict_t *self) 194: { 195: self->monsterinfo.currentmove = &gunner_move_walk; 196: } 197: 198: mframe_t gunner_frames_run [] = 199: { 200: ai_run, 26, NULL, 201: ai_run, 9, NULL, 202: ai_run, 9, NULL, 203: ai_run, 9, NULL, 204: ai_run, 15, NULL, 205: ai_run, 10, NULL, 206: ai_run, 13, NULL, 207: ai_run, 6, NULL 208: }; 209: 210: mmove_t gunner_move_run = {FRAME_run01, FRAME_run08, gunner_frames_run, NULL}; 211: 212: void gunner_run (edict_t *self) 213: { 214: if (self->monsterinfo.aiflags & AI_STAND_GROUND) 215: self->monsterinfo.currentmove = &gunner_move_stand; 216: else 217: self->monsterinfo.currentmove = &gunner_move_run; 218: } 219: 220: mframe_t gunner_frames_runandshoot [] = 221: { 222: ai_run, 32, NULL, 223: ai_run, 15, NULL, 224: ai_run, 10, NULL, 225: ai_run, 18, NULL, 226: ai_run, 8, NULL, 227: ai_run, 20, NULL 228: }; 229: 230: mmove_t gunner_move_runandshoot = {FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, NULL}; 231: 232: void gunner_runandshoot (edict_t *self) 233: { 234: self->monsterinfo.currentmove = &gunner_move_runandshoot; 235: } 236: 237: mframe_t gunner_frames_pain3 [] = 238: { 239: ai_move, -3, NULL, 240: ai_move, 1, NULL, 241: ai_move, 1, NULL, 242: ai_move, 0, NULL, 243: ai_move, 1, NULL 244: }; 245: mmove_t gunner_move_pain3 = {FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run}; 246: 247: mframe_t gunner_frames_pain2 [] = 248: { 249: ai_move, -2, NULL, 250: ai_move, 11, NULL, 251: ai_move, 6, NULL, 252: ai_move, 2, NULL, 253: ai_move, -1, NULL, 254: ai_move, -7, NULL, 255: ai_move, -2, NULL, 256: ai_move, -7, NULL 257: }; 258: mmove_t gunner_move_pain2 = {FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run}; 259: 260: mframe_t gunner_frames_pain1 [] = 261: { 262: ai_move, 2, NULL, 263: ai_move, 0, NULL, 264: ai_move, -5, NULL, 265: ai_move, 3, NULL, 266: ai_move, -1, NULL, 267: ai_move, 0, NULL, 268: ai_move, 0, NULL, 269: ai_move, 0, NULL, 270: ai_move, 0, NULL, 271: ai_move, 1, NULL, 272: ai_move, 1, NULL, 273: ai_move, 2, NULL, 274: ai_move, 1, NULL, 275: ai_move, 0, NULL, 276: ai_move, -2, NULL, 277: ai_move, -2, NULL, 278: ai_move, 0, NULL, 279: ai_move, 0, NULL 280: }; 281: mmove_t gunner_move_pain1 = {FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run}; 282: 283: void gunner_pain (edict_t *self, edict_t *other, float kick, int damage) 284: { 285: if (self->health < (self->max_health / 2)) 286: self->s.skinnum = 1; 287: 288: if (level.time < self->pain_debounce_time) 289: return; 290: 291: self->pain_debounce_time = level.time + 3; 292: 293: if (rand()&1) 294: gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0); 295: else 296: gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0); 297: 298: if (skill->value == 3) 299: return; // no pain anims in nightmare 300: 301: if (damage <= 10) 302: self->monsterinfo.currentmove = &gunner_move_pain3; 303: else if (damage <= 25) 304: self->monsterinfo.currentmove = &gunner_move_pain2; 305: else 306: self->monsterinfo.currentmove = &gunner_move_pain1; 307: } 308: 309: void gunner_dead (edict_t *self) 310: { 311: VectorSet (self->mins, -16, -16, -24); 312: VectorSet (self->maxs, 16, 16, -8); 313: self->movetype = MOVETYPE_TOSS; 314: self->svflags |= SVF_DEADMONSTER; 315: self->nextthink = 0; 316: gi.linkentity (self); 317: } 318: 319: mframe_t gunner_frames_death [] = 320: { 321: ai_move, 0, NULL, 322: ai_move, 0, NULL, 323: ai_move, 0, NULL, 324: ai_move, -7, NULL, 325: ai_move, -3, NULL, 326: ai_move, -5, NULL, 327: ai_move, 8, NULL, 328: ai_move, 6, NULL, 329: ai_move, 0, NULL, 330: ai_move, 0, NULL, 331: ai_move, 0, NULL 332: }; 333: mmove_t gunner_move_death = {FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead}; 334: 335: void gunner_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) 336: { 337: int n; 338: 339: // check for gib 340: if (self->health <= self->gib_health) 341: { 342: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); 343: for (n= 0; n < 2; n++) 344: ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); 345: for (n= 0; n < 4; n++) 346: ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); 347: ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); 348: self->deadflag = DEAD_DEAD; 349: return; 350: } 351: 352: if (self->deadflag == DEAD_DEAD) 353: return; 354: 355: // regular death 356: gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0); 357: self->deadflag = DEAD_DEAD; 358: self->takedamage = DAMAGE_YES; 359: self->monsterinfo.currentmove = &gunner_move_death; 360: } 361: 362: 363: void gunner_duck_down (edict_t *self) 364: { 365: if (self->monsterinfo.aiflags & AI_DUCKED) 366: return; 367: self->monsterinfo.aiflags |= AI_DUCKED; 368: if (skill->value >= 2) 369: { 370: if (random() > 0.5) 371: GunnerGrenade (self); 372: } 373: 374: self->maxs[2] -= 32; 375: self->takedamage = DAMAGE_YES; 376: self->monsterinfo.pausetime = level.time + 1; 377: gi.linkentity (self); 378: } 379: 380: void gunner_duck_hold (edict_t *self) 381: { 382: if (level.time >= self->monsterinfo.pausetime) 383: self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; 384: else 385: self->monsterinfo.aiflags |= AI_HOLD_FRAME; 386: } 387: 388: void gunner_duck_up (edict_t *self) 389: { 390: self->monsterinfo.aiflags &= ~AI_DUCKED; 391: self->maxs[2] += 32; 392: self->takedamage = DAMAGE_AIM; 393: gi.linkentity (self); 394: } 395: 396: mframe_t gunner_frames_duck [] = 397: { 398: ai_move, 1, gunner_duck_down, 399: ai_move, 1, NULL, 400: ai_move, 1, gunner_duck_hold, 401: ai_move, 0, NULL, 402: ai_move, -1, NULL, 403: ai_move, -1, NULL, 404: ai_move, 0, gunner_duck_up, 405: ai_move, -1, NULL 406: }; 407: mmove_t gunner_move_duck = {FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run}; 408: 409: void gunner_dodge (edict_t *self, edict_t *attacker, float eta) 410: { 411: if (random() > 0.25) 412: return; 413: 414: if (!self->enemy) 415: self->enemy = attacker; 416: 417: self->monsterinfo.currentmove = &gunner_move_duck; 418: } 419: 420: 421: void gunner_opengun (edict_t *self) 422: { 423: gi.sound (self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0); 424: } 425: 426: void GunnerFire (edict_t *self) 427: { 428: vec3_t start; 429: vec3_t forward, right; 430: vec3_t target; 431: vec3_t aim; 432: int flash_number; 433: 434: flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216); 435: 436: AngleVectors (self->s.angles, forward, right, NULL); 437: G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); 438: 439: // project enemy back a bit and target there 440: VectorCopy (self->enemy->s.origin, target); 441: VectorMA (target, -0.2, self->enemy->velocity, target); 442: target[2] += self->enemy->viewheight; 443: 444: VectorSubtract (target, start, aim); 445: VectorNormalize (aim); 446: monster_fire_bullet (self, start, aim, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number); 447: } 448: 449: void GunnerGrenade (edict_t *self) 450: { 451: vec3_t start; 452: vec3_t forward, right; 453: vec3_t aim; 454: int flash_number; 455: 456: if (self->s.frame == FRAME_attak105) 457: flash_number = MZ2_GUNNER_GRENADE_1; 458: else if (self->s.frame == FRAME_attak108) 459: flash_number = MZ2_GUNNER_GRENADE_2; 460: else if (self->s.frame == FRAME_attak111) 461: flash_number = MZ2_GUNNER_GRENADE_3; 462: else // (self->s.frame == FRAME_attak114) 463: flash_number = MZ2_GUNNER_GRENADE_4; 464: 465: AngleVectors (self->s.angles, forward, right, NULL); 466: G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start); 467: 468: //FIXME : do a spread -225 -75 75 225 degrees around forward 469: VectorCopy (forward, aim); 470: 471: monster_fire_grenade (self, start, aim, 50, 600, flash_number); 472: } 473: 474: mframe_t gunner_frames_attack_chain [] = 475: { 476: /* 477: ai_charge, 0, NULL, 478: ai_charge, 0, NULL, 479: ai_charge, 0, NULL, 480: ai_charge, 0, NULL, 481: ai_charge, 0, NULL, 482: ai_charge, 0, NULL, 483: ai_charge, 0, NULL, 484: ai_charge, 0, NULL, 485: */ 486: ai_charge, 0, gunner_opengun, 487: ai_charge, 0, NULL, 488: ai_charge, 0, NULL, 489: ai_charge, 0, NULL, 490: ai_charge, 0, NULL, 491: ai_charge, 0, NULL, 492: ai_charge, 0, NULL 493: }; 494: mmove_t gunner_move_attack_chain = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain}; 495: 496: mframe_t gunner_frames_fire_chain [] = 497: { 498: ai_charge, 0, GunnerFire, 499: ai_charge, 0, GunnerFire, 500: ai_charge, 0, GunnerFire, 501: ai_charge, 0, GunnerFire, 502: ai_charge, 0, GunnerFire, 503: ai_charge, 0, GunnerFire, 504: ai_charge, 0, GunnerFire, 505: ai_charge, 0, GunnerFire 506: }; 507: mmove_t gunner_move_fire_chain = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain}; 508: 509: mframe_t gunner_frames_endfire_chain [] = 510: { 511: ai_charge, 0, NULL, 512: ai_charge, 0, NULL, 513: ai_charge, 0, NULL, 514: ai_charge, 0, NULL, 515: ai_charge, 0, NULL, 516: ai_charge, 0, NULL, 517: ai_charge, 0, NULL 518: }; 519: mmove_t gunner_move_endfire_chain = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run}; 520: 521: mframe_t gunner_frames_attack_grenade [] = 522: { 523: ai_charge, 0, NULL, 524: ai_charge, 0, NULL, 525: ai_charge, 0, NULL, 526: ai_charge, 0, NULL, 527: ai_charge, 0, GunnerGrenade, 528: ai_charge, 0, NULL, 529: ai_charge, 0, NULL, 530: ai_charge, 0, GunnerGrenade, 531: ai_charge, 0, NULL, 532: ai_charge, 0, NULL, 533: ai_charge, 0, GunnerGrenade, 534: ai_charge, 0, NULL, 535: ai_charge, 0, NULL, 536: ai_charge, 0, GunnerGrenade, 537: ai_charge, 0, NULL, 538: ai_charge, 0, NULL, 539: ai_charge, 0, NULL, 540: ai_charge, 0, NULL, 541: ai_charge, 0, NULL, 542: ai_charge, 0, NULL, 543: ai_charge, 0, NULL 544: }; 545: mmove_t gunner_move_attack_grenade = {FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run}; 546: 547: void gunner_attack(edict_t *self) 548: { 549: if (range (self, self->enemy) == RANGE_MELEE) 550: { 551: self->monsterinfo.currentmove = &gunner_move_attack_chain; 552: } 553: else 554: { 555: if (random() <= 0.5) 556: self->monsterinfo.currentmove = &gunner_move_attack_grenade; 557: else 558: self->monsterinfo.currentmove = &gunner_move_attack_chain; 559: } 560: } 561: 562: void gunner_fire_chain(edict_t *self) 563: { 564: self->monsterinfo.currentmove = &gunner_move_fire_chain; 565: } 566: 567: void gunner_refire_chain(edict_t *self) 568: { 569: if (self->enemy->health > 0) 570: if ( visible (self, self->enemy) ) 571: if (random() <= 0.5) 572: { 573: self->monsterinfo.currentmove = &gunner_move_fire_chain; 574: return; 575: } 576: self->monsterinfo.currentmove = &gunner_move_endfire_chain; 577: } 578: 579: /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight 580: */ 581: void SP_monster_gunner (edict_t *self) 582: { 583: if (deathmatch->value) 584: { 585: G_FreeEdict (self); 586: return; 587: } 588: 589: sound_death = gi.soundindex ("gunner/death1.wav"); 590: sound_pain = gi.soundindex ("gunner/gunpain2.wav"); 591: sound_pain2 = gi.soundindex ("gunner/gunpain1.wav"); 592: sound_idle = gi.soundindex ("gunner/gunidle1.wav"); 593: sound_open = gi.soundindex ("gunner/gunatck1.wav"); 594: sound_search = gi.soundindex ("gunner/gunsrch1.wav"); 595: sound_sight = gi.soundindex ("gunner/sight1.wav"); 596: 597: gi.soundindex ("gunner/gunatck2.wav"); 598: gi.soundindex ("gunner/gunatck3.wav"); 599: 600: self->movetype = MOVETYPE_STEP; 601: self->solid = SOLID_BBOX; 602: self->s.modelindex = gi.modelindex ("models/monsters/gunner/tris.md2"); 603: VectorSet (self->mins, -16, -16, -24); 604: VectorSet (self->maxs, 16, 16, 32); 605: 606: self->health = 175; 607: self->gib_health = -70; 608: self->mass = 200; 609: 610: self->pain = gunner_pain; 611: self->die = gunner_die; 612: 613: self->monsterinfo.stand = gunner_stand; 614: self->monsterinfo.walk = gunner_walk; 615: self->monsterinfo.run = gunner_run; 616: self->monsterinfo.dodge = gunner_dodge; 617: self->monsterinfo.attack = gunner_attack; 618: self->monsterinfo.melee = NULL; 619: self->monsterinfo.sight = gunner_sight; 620: self->monsterinfo.search = gunner_search; 621: 622: gi.linkentity (self); 623: 624: self->monsterinfo.currentmove = &gunner_move_stand; 625: self->monsterinfo.scale = MODEL_SCALE; 626: 627: walkmonster_start (self); 628: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.