|
|
1.1 ! root 1: /* ! 2: ============================================================================== ! 3: ! 4: black widow, part 2 ! 5: ! 6: ============================================================================== ! 7: */ ! 8: ! 9: // timestamp used to prevent rapid fire of melee attack ! 10: ! 11: #include "g_local.h" ! 12: #include "m_widow2.h" ! 13: ! 14: #define NUM_STALKERS_SPAWNED 6 // max # of stalkers she can spawn ! 15: ! 16: #define DISRUPT_TIME 3 ! 17: ! 18: static int sound_pain1; ! 19: static int sound_pain2; ! 20: static int sound_pain3; ! 21: static int sound_death; ! 22: static int sound_search1; ! 23: static int sound_disrupt; ! 24: static int sound_tentacles_retract; ! 25: ! 26: // sqrt(64*64*2) + sqrt(28*28*2) => 130.1 ! 27: static vec3_t spawnpoints[] = { ! 28: {30, 135, 0}, ! 29: {30, -135, 0} ! 30: }; ! 31: ! 32: static float sweep_angles[] = { ! 33: -40.0, -32.0, -24.0, -16.0, -8.0, 0.0, 8.0, 16.0, 24.0, 32.0, 40.0 ! 34: }; ! 35: ! 36: extern vec3_t stalker_mins, stalker_maxs; ! 37: ! 38: qboolean infront (edict_t *self, edict_t *other); ! 39: void WidowCalcSlots (edict_t *self); ! 40: void WidowPowerups (edict_t *self); ! 41: ! 42: void widow2_run (edict_t *self); ! 43: void widow2_stand (edict_t *self); ! 44: void widow2_dead (edict_t *self); ! 45: void widow2_attack (edict_t *self); ! 46: void widow2_attack_beam (edict_t *self); ! 47: void widow2_reattack_beam (edict_t *self); ! 48: void widow2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); ! 49: void widow_start_spawn (edict_t *self); ! 50: void widow_done_spawn (edict_t *self); ! 51: void widow2_spawn_check (edict_t *self); ! 52: void widow2_prep_spawn (edict_t *self); ! 53: void Widow2SaveBeamTarget(edict_t *self); ! 54: ! 55: // death stuff ! 56: void WidowExplode (edict_t *self); ! 57: void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point); ! 58: void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); ! 59: void ThrowWidowGibReal (edict_t *self, char *gibname, int damage, int type, vec3_t startpos, qboolean large, int hitsound, qboolean fade); ! 60: void ThrowWidowGibSized (edict_t *self, char *gibname, int damage, int type, vec3_t startpos, int hitsound, qboolean fade); ! 61: void ThrowWidowGibLoc (edict_t *self, char *gibname, int damage, int type, vec3_t startpos, qboolean fade); ! 62: void WidowExplosion1 (edict_t *self); ! 63: void WidowExplosion2 (edict_t *self); ! 64: void WidowExplosion3 (edict_t *self); ! 65: void WidowExplosion4 (edict_t *self); ! 66: void WidowExplosion5 (edict_t *self); ! 67: void WidowExplosion6 (edict_t *self); ! 68: void WidowExplosion7 (edict_t *self); ! 69: void WidowExplosionLeg (edict_t *self); ! 70: void ThrowArm1 (edict_t *self); ! 71: void ThrowArm2 (edict_t *self); ! 72: void ClipGibVelocity (edict_t *ent); ! 73: // end of death stuff ! 74: ! 75: // these offsets used by the tongue ! 76: static vec3_t offsets[] = { ! 77: {17.48, 0.10, 68.92}, ! 78: {17.47, 0.29, 68.91}, ! 79: {17.45, 0.53, 68.87}, ! 80: {17.42, 0.78, 68.81}, ! 81: {17.39, 1.02, 68.75}, ! 82: {17.37, 1.20, 68.70}, ! 83: {17.36, 1.24, 68.71}, ! 84: {17.37, 1.21, 68.72}, ! 85: }; ! 86: ! 87: void showme (edict_t *self); ! 88: ! 89: void pauseme (edict_t *self) ! 90: { ! 91: self->monsterinfo.aiflags |= AI_HOLD_FRAME; ! 92: } ! 93: ! 94: void widow2_search (edict_t *self) ! 95: { ! 96: if (random() < 0.5) ! 97: gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0); ! 98: } ! 99: ! 100: void Widow2Beam (edict_t *self) ! 101: { ! 102: vec3_t forward, right, target; ! 103: vec3_t start, targ_angles, vec; ! 104: int flashnum; ! 105: ! 106: if ((!self->enemy) || (!self->enemy->inuse)) ! 107: return; ! 108: ! 109: AngleVectors (self->s.angles, forward, right, NULL); ! 110: ! 111: if ((self->s.frame >= FRAME_fireb05) && (self->s.frame <= FRAME_fireb09)) ! 112: { ! 113: // regular beam attack ! 114: Widow2SaveBeamTarget(self); ! 115: flashnum = MZ2_WIDOW2_BEAMER_1 + self->s.frame - FRAME_fireb05; ! 116: G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); ! 117: VectorCopy (self->pos2, target); ! 118: target[2] += self->enemy->viewheight-10; ! 119: VectorSubtract (target, start, forward); ! 120: VectorNormalize (forward); ! 121: monster_fire_heat (self, start, forward, vec3_origin, 10, 50, flashnum); ! 122: } ! 123: else if ((self->s.frame >= FRAME_spawn04) && (self->s.frame <= FRAME_spawn14)) ! 124: { ! 125: // sweep ! 126: flashnum = MZ2_WIDOW2_BEAM_SWEEP_1 + self->s.frame - FRAME_spawn04; ! 127: G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start); ! 128: VectorSubtract (self->enemy->s.origin, start, target); ! 129: vectoangles2 (target, targ_angles); ! 130: ! 131: VectorCopy (self->s.angles, vec); ! 132: ! 133: vec[PITCH] += targ_angles[PITCH]; ! 134: vec[YAW] -= sweep_angles[flashnum-MZ2_WIDOW2_BEAM_SWEEP_1]; ! 135: ! 136: AngleVectors (vec, forward, NULL, NULL); ! 137: monster_fire_heat (self, start, forward, vec3_origin, 10, 50, flashnum); ! 138: /* ! 139: if (self->s.frame == FRAME_spawn04) ! 140: { ! 141: VectorMA (start, 1024, forward, debugend); ! 142: ! 143: gi.WriteByte (svc_temp_entity); ! 144: gi.WriteByte (TE_DEBUGTRAIL); ! 145: gi.WritePosition (start); ! 146: gi.WritePosition (debugend); ! 147: gi.multicast (start, MULTICAST_ALL); ! 148: ! 149: drawbbox (self); ! 150: self->monsterinfo.aiflags |= AI_HOLD_FRAME|AI_MANUAL_STEERING; ! 151: } ! 152: */ ! 153: } ! 154: else ! 155: { ! 156: if ((g_showlogic) && (g_showlogic->value)) ! 157: gi.dprintf ("bad fire frame for widow2 beam -- tell me you saw this!\n"); ! 158: ! 159: Widow2SaveBeamTarget(self); ! 160: G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_WIDOW2_BEAMER_1], forward, right, start); ! 161: ! 162: VectorCopy (self->pos2, target); ! 163: target[2] += self->enemy->viewheight-10; ! 164: ! 165: VectorSubtract (target, start, forward); ! 166: VectorNormalize (forward); ! 167: ! 168: monster_fire_heat (self, start, forward, vec3_origin, 10, 50, 0); ! 169: } ! 170: } ! 171: ! 172: void Widow2Spawn (edict_t *self) ! 173: { ! 174: vec3_t f, r, u, offset, startpoint, spawnpoint; ! 175: edict_t *ent, *designated_enemy; ! 176: int i; ! 177: ! 178: AngleVectors (self->s.angles, f, r, u); ! 179: ! 180: for (i=0; i < 2; i++) ! 181: { ! 182: VectorCopy (spawnpoints[i], offset); ! 183: ! 184: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 185: ! 186: if (FindSpawnPoint (startpoint, stalker_mins, stalker_maxs, spawnpoint, 64)) ! 187: { ! 188: ent = CreateGroundMonster (spawnpoint, self->s.angles, stalker_mins, stalker_maxs, "monster_stalker", 256); ! 189: ! 190: if (!ent) ! 191: continue; ! 192: ! 193: self->monsterinfo.monster_used++; ! 194: ent->monsterinfo.commander = self; ! 195: if ((g_showlogic) && (g_showlogic->value)) ! 196: gi.dprintf ("widow: post-spawn : %d slots left\n", SELF_SLOTS_LEFT); ! 197: ! 198: ent->nextthink = level.time; ! 199: ent->think (ent); ! 200: ! 201: ent->monsterinfo.aiflags |= AI_SPAWNED_WIDOW|AI_DO_NOT_COUNT|AI_IGNORE_SHOTS; ! 202: ! 203: if (!(coop && coop->value)) ! 204: { ! 205: designated_enemy = self->enemy; ! 206: } ! 207: else ! 208: { ! 209: designated_enemy = PickCoopTarget(ent); ! 210: if (designated_enemy) ! 211: { ! 212: // try to avoid using my enemy ! 213: if (designated_enemy == self->enemy) ! 214: { ! 215: designated_enemy = PickCoopTarget(ent); ! 216: if (designated_enemy) ! 217: { ! 218: if ((g_showlogic) && (g_showlogic->value)) ! 219: { ! 220: gi.dprintf ("PickCoopTarget returned a %s - ", designated_enemy->classname); ! 221: if (designated_enemy->client) ! 222: gi.dprintf ("with name %s\n", designated_enemy->client->pers.netname); ! 223: else ! 224: gi.dprintf ("NOT A CLIENT\n"); ! 225: } ! 226: } ! 227: else ! 228: { ! 229: if ((g_showlogic) && (g_showlogic->value)) ! 230: gi.dprintf ("pick coop failed, using my current enemy\n"); ! 231: designated_enemy = self->enemy; ! 232: } ! 233: } ! 234: } ! 235: else ! 236: { ! 237: if ((g_showlogic) && (g_showlogic->value)) ! 238: gi.dprintf ("pick coop failed, using my current enemy\n"); ! 239: designated_enemy = self->enemy; ! 240: } ! 241: } ! 242: ! 243: if ((designated_enemy->inuse) && (designated_enemy->health > 0)) ! 244: { ! 245: ent->enemy = designated_enemy; ! 246: FoundTarget (ent); ! 247: ent->monsterinfo.attack(ent); ! 248: } ! 249: } ! 250: } ! 251: } ! 252: ! 253: void widow2_spawn_check (edict_t *self) ! 254: { ! 255: Widow2Beam(self); ! 256: Widow2Spawn (self); ! 257: } ! 258: ! 259: void widow2_ready_spawn (edict_t *self) ! 260: { ! 261: vec3_t f, r, u, offset, startpoint, spawnpoint; ! 262: int i; ! 263: ! 264: Widow2Beam(self); ! 265: AngleVectors (self->s.angles, f, r, u); ! 266: ! 267: for (i=0; i < 2; i++) ! 268: { ! 269: VectorCopy (spawnpoints[i], offset); ! 270: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 271: if (FindSpawnPoint (startpoint, stalker_mins, stalker_maxs, spawnpoint, 64)) ! 272: { ! 273: SpawnGrow_Spawn (spawnpoint, 1); ! 274: } ! 275: } ! 276: } ! 277: ! 278: mframe_t widow2_frames_stand [] = ! 279: { ! 280: // ai_stand, 0, drawbbox ! 281: ai_stand, 0, NULL ! 282: }; ! 283: mmove_t widow2_move_stand = {FRAME_blackwidow3, FRAME_blackwidow3, widow2_frames_stand, NULL}; ! 284: ! 285: mframe_t widow2_frames_walk [] = ! 286: { ! 287: // ai_walk, 9.01, drawbbox, ! 288: ai_walk, 9.01, NULL, ! 289: ai_walk, 7.55, NULL, ! 290: ai_walk, 7.01, NULL, ! 291: ai_walk, 6.66, NULL, ! 292: ai_walk, 6.20, NULL, ! 293: ai_walk, 5.78, NULL, ! 294: ai_walk, 7.25, NULL, ! 295: ai_walk, 8.37, NULL, ! 296: ai_walk, 10.41, NULL ! 297: }; ! 298: mmove_t widow2_move_walk = {FRAME_walk01, FRAME_walk09, widow2_frames_walk, NULL}; ! 299: ! 300: ! 301: mframe_t widow2_frames_run [] = ! 302: { ! 303: // ai_run, 9.01, drawbbox, ! 304: ai_run, 9.01, NULL, ! 305: ai_run, 7.55, NULL, ! 306: ai_run, 7.01, NULL, ! 307: ai_run, 6.66, NULL, ! 308: ai_run, 6.20, NULL, ! 309: ai_run, 5.78, NULL, ! 310: ai_run, 7.25, NULL, ! 311: ai_run, 8.37, NULL, ! 312: ai_run, 10.41, NULL ! 313: }; ! 314: mmove_t widow2_move_run = {FRAME_walk01, FRAME_walk09, widow2_frames_run, NULL}; ! 315: ! 316: mframe_t widow2_frames_attack_pre_beam [] = ! 317: { ! 318: ai_charge, 4, NULL, ! 319: ai_charge, 4, NULL, ! 320: ai_charge, 4, NULL, ! 321: ai_charge, 4, widow2_attack_beam ! 322: }; ! 323: mmove_t widow2_move_attack_pre_beam = {FRAME_fireb01, FRAME_fireb04, widow2_frames_attack_pre_beam, NULL}; ! 324: ! 325: ! 326: // Loop this ! 327: mframe_t widow2_frames_attack_beam [] = ! 328: { ! 329: ai_charge, 0, Widow2Beam, ! 330: ai_charge, 0, Widow2Beam, ! 331: ai_charge, 0, Widow2Beam, ! 332: ai_charge, 0, Widow2Beam, ! 333: ai_charge, 0, widow2_reattack_beam ! 334: }; ! 335: mmove_t widow2_move_attack_beam = {FRAME_fireb05, FRAME_fireb09, widow2_frames_attack_beam, NULL}; ! 336: ! 337: mframe_t widow2_frames_attack_post_beam [] = ! 338: { ! 339: ai_charge, 4, NULL, ! 340: ai_charge, 4, NULL, ! 341: ai_charge, 4, NULL ! 342: }; ! 343: mmove_t widow2_move_attack_post_beam = {FRAME_fireb06, FRAME_fireb07, widow2_frames_attack_post_beam, widow2_run}; ! 344: ! 345: ! 346: void WidowDisrupt (edict_t *self) ! 347: { ! 348: vec3_t start; ! 349: vec3_t dir; ! 350: vec3_t forward, right; ! 351: float len; ! 352: ! 353: AngleVectors (self->s.angles, forward, right, NULL); ! 354: G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_WIDOW_DISRUPTOR], forward, right, start); ! 355: ! 356: VectorSubtract (self->pos1, self->enemy->s.origin, dir); ! 357: len = VectorLength (dir); ! 358: ! 359: if (len < 30) ! 360: { ! 361: // if ((g_showlogic) && (g_showlogic->value)) ! 362: // gi.dprintf ("target locked - dist %2.2f\n", len); ! 363: // calc direction to where we targeted ! 364: VectorSubtract (self->pos1, start, dir); ! 365: VectorNormalize (dir); ! 366: ! 367: monster_fire_tracker(self, start, dir, 20, 500, self->enemy, MZ2_WIDOW_DISRUPTOR); ! 368: } ! 369: else ! 370: { ! 371: // if ((g_showlogic) && (g_showlogic->value)) ! 372: // gi.dprintf ("target missed - dist %2.2f\n", len); ! 373: ! 374: PredictAim (self->enemy, start, 1200, true, 0, dir, NULL); ! 375: ! 376: // VectorSubtract (self->enemy->s.origin, start, dir); ! 377: // VectorNormalize (dir); ! 378: monster_fire_tracker(self, start, dir, 20, 1200, NULL, MZ2_WIDOW_DISRUPTOR); ! 379: } ! 380: } ! 381: ! 382: void Widow2SaveDisruptLoc (edict_t *self) ! 383: { ! 384: if (self->enemy && self->enemy->inuse) ! 385: { ! 386: VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot ! 387: self->pos1[2] += self->enemy->viewheight; ! 388: } ! 389: else ! 390: VectorCopy (vec3_origin, self->pos1); ! 391: }; ! 392: ! 393: void widow2_disrupt_reattack (edict_t *self) ! 394: { ! 395: float luck; ! 396: ! 397: luck = random(); ! 398: ! 399: if (luck < (0.25 + ((float)(skill->value))*0.15)) ! 400: self->monsterinfo.nextframe = FRAME_firea01; ! 401: } ! 402: ! 403: mframe_t widow2_frames_attack_disrupt [] = ! 404: { ! 405: ai_charge, 2, NULL, ! 406: ai_charge, 2, NULL, ! 407: ai_charge, 2, Widow2SaveDisruptLoc, ! 408: ai_charge, -20, WidowDisrupt, ! 409: ai_charge, 2, NULL, ! 410: ai_charge, 2, NULL, ! 411: ai_charge, 2, widow2_disrupt_reattack ! 412: }; ! 413: mmove_t widow2_move_attack_disrupt = {FRAME_firea01, FRAME_firea07, widow2_frames_attack_disrupt, widow2_run}; ! 414: ! 415: void Widow2SaveBeamTarget (edict_t *self) ! 416: { ! 417: if (self->enemy && self->enemy->inuse) ! 418: { ! 419: VectorCopy (self->pos1, self->pos2); ! 420: VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot ! 421: } ! 422: else ! 423: { ! 424: VectorCopy (vec3_origin, self->pos1); ! 425: VectorCopy (vec3_origin, self->pos2); ! 426: } ! 427: } ! 428: ! 429: void Widow2BeamTargetRemove (edict_t *self) ! 430: { ! 431: VectorCopy (vec3_origin, self->pos1); ! 432: VectorCopy (vec3_origin, self->pos2); ! 433: } ! 434: ! 435: void Widow2StartSweep (edict_t *self) ! 436: { ! 437: Widow2SaveBeamTarget (self); ! 438: } ! 439: ! 440: mframe_t widow2_frames_spawn [] = ! 441: { ! 442: ai_charge, 0, NULL, ! 443: ai_charge, 0, NULL, ! 444: ai_charge, 0, widow_start_spawn, ! 445: ai_charge, 0, Widow2Beam, ! 446: ai_charge, 0, Widow2Beam, //5 ! 447: ai_charge, 0, Widow2Beam, ! 448: ai_charge, 0, Widow2Beam, ! 449: ai_charge, 0, Widow2Beam, ! 450: ai_charge, 0, Widow2Beam, ! 451: ai_charge, 0, widow2_ready_spawn, //10 ! 452: ai_charge, 0, Widow2Beam, ! 453: ai_charge, 0, Widow2Beam, ! 454: ai_charge, 0, Widow2Beam, ! 455: ai_charge, 0, widow2_spawn_check, ! 456: ai_charge, 0, NULL, //15 ! 457: ai_charge, 0, NULL, ! 458: ai_charge, 0, NULL, ! 459: ai_charge, 0, widow2_reattack_beam ! 460: }; ! 461: mmove_t widow2_move_spawn = {FRAME_spawn01, FRAME_spawn18, widow2_frames_spawn, NULL}; ! 462: ! 463: static qboolean widow2_tongue_attack_ok (vec3_t start, vec3_t end, float range) ! 464: { ! 465: vec3_t dir, angles; ! 466: ! 467: // check for max distance ! 468: VectorSubtract (start, end, dir); ! 469: if (VectorLength(dir) > range) ! 470: return false; ! 471: ! 472: // check for min/max pitch ! 473: vectoangles (dir, angles); ! 474: if (angles[0] < -180) ! 475: angles[0] += 360; ! 476: if (fabs(angles[0]) > 30) ! 477: return false; ! 478: ! 479: return true; ! 480: } ! 481: ! 482: void Widow2Tongue (edict_t *self) ! 483: { ! 484: vec3_t f, r, u; ! 485: vec3_t start, end, dir; ! 486: trace_t tr; ! 487: ! 488: AngleVectors (self->s.angles, f, r, u); ! 489: G_ProjectSource2 (self->s.origin, offsets[self->s.frame - FRAME_tongs01], f, r, u, start); ! 490: VectorCopy (self->enemy->s.origin, end); ! 491: if (!widow2_tongue_attack_ok(start, end, 256)) ! 492: { ! 493: end[2] = self->enemy->s.origin[2] + self->enemy->maxs[2] - 8; ! 494: if (!widow2_tongue_attack_ok(start, end, 256)) ! 495: { ! 496: end[2] = self->enemy->s.origin[2] + self->enemy->mins[2] + 8; ! 497: if (!widow2_tongue_attack_ok(start, end, 256)) ! 498: return; ! 499: } ! 500: } ! 501: VectorCopy (self->enemy->s.origin, end); ! 502: ! 503: tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT); ! 504: if (tr.ent != self->enemy) ! 505: return; ! 506: ! 507: gi.sound (self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0); ! 508: ! 509: gi.WriteByte (svc_temp_entity); ! 510: gi.WriteByte (TE_PARASITE_ATTACK); ! 511: gi.WriteShort (self - g_edicts); ! 512: gi.WritePosition (start); ! 513: gi.WritePosition (end); ! 514: gi.multicast (self->s.origin, MULTICAST_PVS); ! 515: ! 516: VectorSubtract (start, end, dir); ! 517: T_Damage (self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, 2, 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN); ! 518: } ! 519: ! 520: void Widow2TonguePull (edict_t *self) ! 521: { ! 522: vec3_t vec; ! 523: float len; ! 524: vec3_t f, r, u; ! 525: vec3_t start, end; ! 526: ! 527: if ((!self->enemy) || (!self->enemy->inuse)) ! 528: { ! 529: self->monsterinfo.run (self); ! 530: return; ! 531: } ! 532: ! 533: AngleVectors (self->s.angles, f, r, u); ! 534: G_ProjectSource2 (self->s.origin, offsets[self->s.frame - FRAME_tongs01], f, r, u, start); ! 535: VectorCopy (self->enemy->s.origin, end); ! 536: ! 537: if (!widow2_tongue_attack_ok(start, end, 256)) ! 538: { ! 539: return; ! 540: } ! 541: ! 542: if (self->enemy->groundentity) ! 543: { ! 544: self->enemy->s.origin[2] += 1; ! 545: self->enemy->groundentity = NULL; ! 546: // interesting, you don't have to relink the player ! 547: } ! 548: ! 549: VectorSubtract (self->s.origin, self->enemy->s.origin, vec); ! 550: len = VectorLength (vec); ! 551: if (self->enemy->client) ! 552: { ! 553: VectorNormalize (vec); ! 554: VectorMA (self->enemy->velocity, 1000, vec, self->enemy->velocity); ! 555: } ! 556: else ! 557: { ! 558: self->enemy->ideal_yaw = vectoyaw(vec); ! 559: M_ChangeYaw (self->enemy); ! 560: VectorScale (f, 1000, self->enemy->velocity); ! 561: } ! 562: } ! 563: ! 564: void Widow2Crunch (edict_t *self) ! 565: { ! 566: vec3_t aim; ! 567: ! 568: if ((!self->enemy) || (!self->enemy->inuse)) ! 569: { ! 570: self->monsterinfo.run (self); ! 571: return; ! 572: } ! 573: ! 574: Widow2TonguePull (self); ! 575: ! 576: // 70 + 32 ! 577: VectorSet (aim, 150, 0, 4); ! 578: if (self->s.frame != FRAME_tongs07) ! 579: fire_hit (self, aim, 20 + (rand() % 6), 0); ! 580: else ! 581: { ! 582: if (self->enemy->groundentity) ! 583: fire_hit (self, aim, (20 + (rand() % 6)), 500); ! 584: else // not as much kick if they're in the air .. makes it harder to land on her head ! 585: fire_hit (self, aim, (20 + (rand() % 6)), 250); ! 586: } ! 587: } ! 588: ! 589: void Widow2Toss (edict_t *self) ! 590: { ! 591: self->timestamp = level.time + 3; ! 592: return; ! 593: } ! 594: ! 595: mframe_t widow2_frames_tongs [] = ! 596: { ! 597: ai_charge, 0, Widow2Tongue, ! 598: ai_charge, 0, Widow2Tongue, ! 599: ai_charge, 0, Widow2Tongue, ! 600: ai_charge, 0, Widow2TonguePull, ! 601: ai_charge, 0, Widow2TonguePull, //5 ! 602: ai_charge, 0, Widow2TonguePull, ! 603: ai_charge, 0, Widow2Crunch, ! 604: ai_charge, 0, Widow2Toss ! 605: }; ! 606: mmove_t widow2_move_tongs = {FRAME_tongs01, FRAME_tongs08, widow2_frames_tongs, widow2_run}; ! 607: ! 608: mframe_t widow2_frames_pain [] = ! 609: { ! 610: ai_move, 0, NULL, ! 611: ai_move, 0, NULL, ! 612: ai_move, 0, NULL, ! 613: ai_move, 0, NULL, ! 614: ai_move, 0, NULL ! 615: }; ! 616: mmove_t widow2_move_pain = {FRAME_pain01, FRAME_pain05, widow2_frames_pain, widow2_run}; ! 617: ! 618: mframe_t widow2_frames_death [] = ! 619: { ! 620: ai_move, 0, NULL, ! 621: ai_move, 0, NULL, ! 622: ai_move, 0, WidowExplosion1, // 3 boom ! 623: ai_move, 0, NULL, ! 624: ai_move, 0, NULL, // 5 ! 625: ! 626: ai_move, 0, WidowExplosion2, // 6 boom ! 627: ai_move, 0, NULL, ! 628: ai_move, 0, NULL, ! 629: ai_move, 0, NULL, ! 630: ai_move, 0, NULL, // 10 ! 631: ! 632: ai_move, 0, NULL, ! 633: ai_move, 0, NULL, // 12 ! 634: ai_move, 0, NULL, ! 635: ai_move, 0, NULL, ! 636: ai_move, 0, NULL, // 15 ! 637: ! 638: ai_move, 0, NULL, ! 639: ai_move, 0, NULL, ! 640: ai_move, 0, WidowExplosion3, // 18 ! 641: ai_move, 0, NULL, // 19 ! 642: ai_move, 0, NULL, // 20 ! 643: ! 644: ai_move, 0, NULL, ! 645: ai_move, 0, NULL, ! 646: ai_move, 0, NULL, ! 647: ai_move, 0, NULL, ! 648: ai_move, 0, WidowExplosion4, // 25 ! 649: ! 650: ai_move, 0, NULL, // 26 ! 651: ai_move, 0, NULL, ! 652: ai_move, 0, NULL, ! 653: ai_move, 0, WidowExplosion5, ! 654: ai_move, 0, WidowExplosionLeg, // 30 ! 655: ! 656: ai_move, 0, NULL, ! 657: ai_move, 0, NULL, ! 658: ai_move, 0, NULL, ! 659: ai_move, 0, WidowExplosion6, ! 660: ai_move, 0, NULL, // 35 ! 661: ! 662: ai_move, 0, NULL, ! 663: ai_move, 0, NULL, ! 664: ai_move, 0, WidowExplosion7, ! 665: ai_move, 0, NULL, ! 666: ai_move, 0, NULL, // 40 ! 667: ! 668: ai_move, 0, NULL, ! 669: ai_move, 0, NULL, ! 670: ai_move, 0, NULL, ! 671: ai_move, 0, WidowExplode // 44 ! 672: }; ! 673: mmove_t widow2_move_death = {FRAME_death01, FRAME_death44, widow2_frames_death, NULL}; ! 674: ! 675: void widow2_start_searching (edict_t *self); ! 676: void widow2_keep_searching (edict_t *self); ! 677: void widow2_finaldeath (edict_t *self); ! 678: ! 679: mframe_t widow2_frames_dead [] = ! 680: { ! 681: ai_move, 0, widow2_start_searching, ! 682: ai_move, 0, NULL, ! 683: ai_move, 0, NULL, ! 684: ai_move, 0, NULL, ! 685: ai_move, 0, NULL, ! 686: ! 687: ai_move, 0, NULL, ! 688: ai_move, 0, NULL, ! 689: ai_move, 0, NULL, ! 690: ai_move, 0, NULL, ! 691: ai_move, 0, NULL, ! 692: ! 693: ai_move, 0, NULL, ! 694: ai_move, 0, NULL, ! 695: ai_move, 0, NULL, ! 696: ai_move, 0, NULL, ! 697: ai_move, 0, widow2_keep_searching ! 698: }; ! 699: mmove_t widow2_move_dead = {FRAME_dthsrh01, FRAME_dthsrh15, widow2_frames_dead, NULL}; ! 700: ! 701: mframe_t widow2_frames_really_dead [] = ! 702: { ! 703: ai_move, 0, NULL, ! 704: ai_move, 0, NULL, ! 705: ai_move, 0, NULL, ! 706: ai_move, 0, NULL, ! 707: ai_move, 0, NULL, ! 708: ! 709: ai_move, 0, NULL, ! 710: ai_move, 0, widow2_finaldeath ! 711: }; ! 712: mmove_t widow2_move_really_dead = {FRAME_dthsrh16, FRAME_dthsrh22, widow2_frames_really_dead, NULL}; ! 713: ! 714: void widow2_start_searching (edict_t *self) ! 715: { ! 716: self->count = 0; ! 717: } ! 718: ! 719: void widow2_keep_searching (edict_t *self) ! 720: { ! 721: if (self->count <= 2) ! 722: { ! 723: self->monsterinfo.currentmove = &widow2_move_dead; ! 724: self->s.frame = FRAME_dthsrh01; ! 725: self->count++; ! 726: return; ! 727: } ! 728: ! 729: self->monsterinfo.currentmove = &widow2_move_really_dead; ! 730: } ! 731: ! 732: void widow2_finaldeath (edict_t *self) ! 733: { ! 734: VectorSet (self->mins, -70, -70, 0); ! 735: VectorSet (self->maxs, 70, 70, 80); ! 736: self->movetype = MOVETYPE_TOSS; ! 737: // self->svflags |= SVF_DEADMONSTER; ! 738: self->takedamage = DAMAGE_YES; ! 739: self->nextthink = 0; ! 740: gi.linkentity (self); ! 741: } ! 742: ! 743: void widow2_stand (edict_t *self) ! 744: { ! 745: // gi.dprintf ("widow2 stand\n"); ! 746: self->monsterinfo.currentmove = &widow2_move_stand; ! 747: } ! 748: ! 749: void widow2_run (edict_t *self) ! 750: { ! 751: ! 752: // gi.dprintf ("widow2 run - %2.2f - %s \n", level.time, self->enemy->classname); ! 753: self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; ! 754: ! 755: if (self->monsterinfo.aiflags & AI_STAND_GROUND) ! 756: self->monsterinfo.currentmove = &widow2_move_stand; ! 757: else ! 758: self->monsterinfo.currentmove = &widow2_move_run; ! 759: } ! 760: ! 761: void widow2_walk (edict_t *self) ! 762: { ! 763: self->monsterinfo.currentmove = &widow2_move_walk; ! 764: } ! 765: ! 766: void widow2_melee (edict_t *self) ! 767: { ! 768: self->monsterinfo.currentmove = &widow2_move_tongs; ! 769: } ! 770: ! 771: void widow2_attack (edict_t *self) ! 772: { ! 773: float range, luck; ! 774: qboolean blocked = false; ! 775: ! 776: if (self->monsterinfo.aiflags & AI_BLOCKED) ! 777: { ! 778: blocked = true; ! 779: self->monsterinfo.aiflags &= ~AI_BLOCKED; ! 780: } ! 781: ! 782: // gi.dprintf ("widow2 attack\n"); ! 783: ! 784: if (!self->enemy) ! 785: return; ! 786: ! 787: if (self->bad_area) ! 788: { ! 789: if ((random() < 0.1) || (level.time < self->monsterinfo.attack_finished)) ! 790: self->monsterinfo.currentmove = &widow2_move_attack_pre_beam; ! 791: else ! 792: { ! 793: gi.sound (self, CHAN_WEAPON, sound_disrupt, 1, ATTN_NORM, 0); ! 794: self->monsterinfo.currentmove = &widow2_move_attack_disrupt; ! 795: } ! 796: return; ! 797: } ! 798: ! 799: WidowCalcSlots(self); ! 800: ! 801: // if we can't see the target, spawn stuff ! 802: if ((self->monsterinfo.attack_state == AS_BLIND) && (SELF_SLOTS_LEFT >= 2)) ! 803: { ! 804: self->monsterinfo.currentmove = &widow2_move_spawn; ! 805: return; ! 806: } ! 807: ! 808: // accept bias towards spawning ! 809: if (blocked && (SELF_SLOTS_LEFT >= 2)) ! 810: { ! 811: self->monsterinfo.currentmove = &widow2_move_spawn; ! 812: return; ! 813: } ! 814: ! 815: range = realrange (self, self->enemy); ! 816: ! 817: if (range < 600) ! 818: { ! 819: luck = random(); ! 820: if (SELF_SLOTS_LEFT >= 2) ! 821: { ! 822: if (luck <= 0.40) ! 823: self->monsterinfo.currentmove = &widow2_move_attack_pre_beam; ! 824: else if ((luck <= 0.7) && !(level.time < self->monsterinfo.attack_finished)) ! 825: { ! 826: gi.sound (self, CHAN_WEAPON, sound_disrupt, 1, ATTN_NORM, 0); ! 827: self->monsterinfo.currentmove = &widow2_move_attack_disrupt; ! 828: } ! 829: else ! 830: self->monsterinfo.currentmove = &widow2_move_spawn; ! 831: } ! 832: else ! 833: { ! 834: if ((luck <= 0.50) || (level.time < self->monsterinfo.attack_finished)) ! 835: self->monsterinfo.currentmove = &widow2_move_attack_pre_beam; ! 836: else ! 837: { ! 838: gi.sound (self, CHAN_WEAPON, sound_disrupt, 1, ATTN_NORM, 0); ! 839: self->monsterinfo.currentmove = &widow2_move_attack_disrupt; ! 840: } ! 841: } ! 842: } ! 843: else ! 844: { ! 845: luck = random(); ! 846: if (SELF_SLOTS_LEFT >= 2) ! 847: { ! 848: if (luck < 0.3) ! 849: self->monsterinfo.currentmove = &widow2_move_attack_pre_beam; ! 850: else if ((luck < 0.65) || (level.time < self->monsterinfo.attack_finished)) ! 851: self->monsterinfo.currentmove = &widow2_move_spawn; ! 852: else ! 853: { ! 854: gi.sound (self, CHAN_WEAPON, sound_disrupt, 1, ATTN_NORM, 0); ! 855: self->monsterinfo.currentmove = &widow2_move_attack_disrupt; ! 856: } ! 857: } ! 858: else ! 859: { ! 860: if ((luck < 0.45) || (level.time < self->monsterinfo.attack_finished)) ! 861: self->monsterinfo.currentmove = &widow2_move_attack_pre_beam; ! 862: else ! 863: { ! 864: gi.sound (self, CHAN_WEAPON, sound_disrupt, 1, ATTN_NORM, 0); ! 865: self->monsterinfo.currentmove = &widow2_move_attack_disrupt; ! 866: } ! 867: } ! 868: } ! 869: } ! 870: ! 871: void widow2_attack_beam (edict_t *self) ! 872: { ! 873: self->monsterinfo.currentmove = &widow2_move_attack_beam; ! 874: } ! 875: ! 876: void widow2_reattack_beam (edict_t *self) ! 877: { ! 878: self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING; ! 879: ! 880: if ( infront(self, self->enemy) ) ! 881: if (random() <= 0.5) ! 882: if ((random() < 0.7) || (SELF_SLOTS_LEFT < 2)) ! 883: self->monsterinfo.currentmove = &widow2_move_attack_beam; ! 884: else ! 885: self->monsterinfo.currentmove = &widow2_move_spawn; ! 886: else ! 887: self->monsterinfo.currentmove = &widow2_move_attack_post_beam; ! 888: else ! 889: self->monsterinfo.currentmove = &widow2_move_attack_post_beam; ! 890: } ! 891: ! 892: ! 893: ! 894: void widow2_pain (edict_t *self, edict_t *other, float kick, int damage) ! 895: { ! 896: if (self->health < (self->max_health / 2)) ! 897: self->s.skinnum = 1; ! 898: ! 899: if (skill->value == 3) ! 900: return; // no pain anims in nightmare ! 901: ! 902: // gi.dprintf ("widow2 pain\n"); ! 903: if (level.time < self->pain_debounce_time) ! 904: return; ! 905: ! 906: self->pain_debounce_time = level.time + 3; ! 907: ! 908: if (damage < 15) ! 909: { ! 910: gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0); ! 911: } ! 912: else if (damage < 75) ! 913: { ! 914: gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0); ! 915: if ((skill->value < 3) && (random() < (0.6 - (0.2*((float)skill->value))))) ! 916: { ! 917: self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING; ! 918: self->monsterinfo.currentmove = &widow2_move_pain; ! 919: } ! 920: } ! 921: else ! 922: { ! 923: gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0); ! 924: if ((skill->value < 3) && (random() < (0.75 - (0.1*((float)skill->value))))) ! 925: { ! 926: self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING; ! 927: self->monsterinfo.currentmove = &widow2_move_pain; ! 928: } ! 929: } ! 930: } ! 931: ! 932: void widow2_dead (edict_t *self) ! 933: { ! 934: } ! 935: ! 936: void KillChildren (edict_t *self) ! 937: { ! 938: edict_t *ent; ! 939: int field; ! 940: ! 941: ent = NULL; ! 942: field = FOFS(classname); ! 943: while (1) ! 944: { ! 945: ent = G_Find (ent, field, "monster_stalker"); ! 946: if(!ent) ! 947: return; ! 948: ! 949: // FIXME - may need to stagger ! 950: if ((ent->inuse) && (ent->health > 0)) ! 951: T_Damage (ent, self, self, vec3_origin, self->enemy->s.origin, vec3_origin, (ent->health + 1), 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN); ! 952: } ! 953: } ! 954: ! 955: void widow2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) ! 956: { ! 957: int n; ! 958: ! 959: // check for gib ! 960: if (self->health <= self->gib_health) ! 961: { ! 962: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); ! 963: for (n= 0; n < 2; n++) ! 964: ThrowWidowGibLoc (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC, NULL, false); ! 965: for (n= 0; n < 3; n++) ! 966: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC, NULL, false); ! 967: for (n= 0; n < 3; n++) ! 968: { ! 969: ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib1/tris.md2", damage, GIB_METALLIC, NULL, ! 970: 0, false); ! 971: ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib2/tris.md2", damage, GIB_METALLIC, NULL, ! 972: gi.soundindex ("misc/fhit3.wav"), false); ! 973: } ! 974: for (n= 0; n < 2; n++) ! 975: { ! 976: ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib3/tris.md2", damage, GIB_METALLIC, NULL, ! 977: 0, false); ! 978: ThrowWidowGibSized (self, "models/monsters/blackwidow/gib3/tris.md2", damage, GIB_METALLIC, NULL, ! 979: 0, false); ! 980: } ! 981: ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC); ! 982: ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); ! 983: self->deadflag = DEAD_DEAD; ! 984: return; ! 985: } ! 986: ! 987: if (self->deadflag == DEAD_DEAD) ! 988: return; ! 989: ! 990: gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0); ! 991: self->deadflag = DEAD_DEAD; ! 992: self->takedamage = DAMAGE_NO; ! 993: self->count = 0; ! 994: KillChildren (self); ! 995: self->monsterinfo.quad_framenum = 0; ! 996: self->monsterinfo.double_framenum = 0; ! 997: self->monsterinfo.invincible_framenum = 0; ! 998: self->monsterinfo.currentmove = &widow2_move_death; ! 999: } ! 1000: ! 1001: qboolean Widow2_CheckAttack (edict_t *self) ! 1002: { ! 1003: vec3_t spot1, spot2; ! 1004: vec3_t temp; ! 1005: float chance; ! 1006: trace_t tr; ! 1007: qboolean enemy_infront; ! 1008: int enemy_range; ! 1009: float enemy_yaw; ! 1010: float real_enemy_range; ! 1011: vec3_t f, r, u; ! 1012: ! 1013: if (!self->enemy) ! 1014: return false; ! 1015: ! 1016: WidowPowerups(self); ! 1017: ! 1018: if ((random() < 0.8) && (SELF_SLOTS_LEFT >= 2) && (realrange(self, self->enemy) > 150)) ! 1019: { ! 1020: self->monsterinfo.aiflags |= AI_BLOCKED; ! 1021: self->monsterinfo.attack_state = AS_MISSILE; ! 1022: return true; ! 1023: } ! 1024: ! 1025: if (self->enemy->health > 0) ! 1026: { ! 1027: // see if any entities are in the way of the shot ! 1028: VectorCopy (self->s.origin, spot1); ! 1029: spot1[2] += self->viewheight; ! 1030: VectorCopy (self->enemy->s.origin, spot2); ! 1031: spot2[2] += self->enemy->viewheight; ! 1032: ! 1033: tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA); ! 1034: ! 1035: // do we have a clear shot? ! 1036: if (tr.ent != self->enemy) ! 1037: { ! 1038: // go ahead and spawn stuff if we're mad a a client ! 1039: if (self->enemy->client && SELF_SLOTS_LEFT >= 2) ! 1040: { ! 1041: self->monsterinfo.attack_state = AS_BLIND; ! 1042: return true; ! 1043: } ! 1044: ! 1045: // PGM - we want them to go ahead and shoot at info_notnulls if they can. ! 1046: if(self->enemy->solid != SOLID_NOT || tr.fraction < 1.0) //PGM ! 1047: return false; ! 1048: } ! 1049: } ! 1050: ! 1051: enemy_infront = infront(self, self->enemy); ! 1052: ! 1053: enemy_range = range(self, self->enemy); ! 1054: VectorSubtract (self->enemy->s.origin, self->s.origin, temp); ! 1055: enemy_yaw = vectoyaw2(temp); ! 1056: ! 1057: self->ideal_yaw = enemy_yaw; ! 1058: ! 1059: // melee attack ! 1060: if (self->timestamp < level.time) ! 1061: { ! 1062: real_enemy_range = realrange (self, self->enemy); ! 1063: if (real_enemy_range < 300) ! 1064: { ! 1065: AngleVectors (self->s.angles, f, r, u); ! 1066: G_ProjectSource2 (self->s.origin, offsets[0], f, r, u, spot1); ! 1067: VectorCopy (self->enemy->s.origin, spot2); ! 1068: if (widow2_tongue_attack_ok(spot1, spot2, 256)) ! 1069: { ! 1070: // melee attack ok ! 1071: ! 1072: // be nice in easy mode ! 1073: if (skill->value == 0 && (rand()&3) ) ! 1074: return false; ! 1075: ! 1076: if (self->monsterinfo.melee) ! 1077: self->monsterinfo.attack_state = AS_MELEE; ! 1078: else ! 1079: self->monsterinfo.attack_state = AS_MISSILE; ! 1080: return true; ! 1081: } ! 1082: } ! 1083: } ! 1084: ! 1085: if (level.time < self->monsterinfo.attack_finished) ! 1086: return false; ! 1087: ! 1088: if (self->monsterinfo.aiflags & AI_STAND_GROUND) ! 1089: { ! 1090: chance = 0.4; ! 1091: } ! 1092: else if (enemy_range == RANGE_NEAR) ! 1093: { ! 1094: chance = 0.8; ! 1095: } ! 1096: else if (enemy_range == RANGE_MID) ! 1097: { ! 1098: chance = 0.8; ! 1099: } ! 1100: else if (enemy_range == RANGE_FAR) ! 1101: { ! 1102: chance = 0.5; ! 1103: } ! 1104: ! 1105: // PGM - go ahead and shoot every time if it's a info_notnull ! 1106: if ((random () < chance) || (self->enemy->solid == SOLID_NOT)) ! 1107: { ! 1108: self->monsterinfo.attack_state = AS_MISSILE; ! 1109: // self->monsterinfo.attack_finished = level.time + 1.0 + 2*random(); ! 1110: return true; ! 1111: } ! 1112: ! 1113: return false; ! 1114: } ! 1115: ! 1116: void Widow2Precache () ! 1117: { ! 1118: // cache in all of the stalker stuff, widow stuff, spawngro stuff, gibs ! 1119: gi.soundindex ("parasite/parpain1.wav"); ! 1120: gi.soundindex ("parasite/parpain2.wav"); ! 1121: gi.soundindex ("parasite/pardeth1.wav"); ! 1122: gi.soundindex ("parasite/paratck1.wav"); ! 1123: gi.soundindex ("parasite/parsght1.wav"); ! 1124: gi.soundindex ("infantry/melee2.wav"); ! 1125: gi.soundindex ("misc/fhit3.wav"); ! 1126: ! 1127: gi.soundindex ("tank/tnkatck3.wav"); ! 1128: gi.soundindex ("weapons/disrupt.wav"); ! 1129: gi.soundindex ("weapons/disint2.wav"); ! 1130: ! 1131: gi.modelindex ("models/monsters/stalker/tris.md2"); ! 1132: gi.modelindex ("models/items/spawngro2/tris.md2"); ! 1133: gi.modelindex ("models/objects/gibs/sm_metal/tris.md2"); ! 1134: gi.modelindex ("models/proj/laser2/tris.md2"); ! 1135: gi.modelindex ("models/proj/disintegrator/tris.md2"); ! 1136: ! 1137: gi.modelindex ("models/monsters/blackwidow/gib1/tris.md2"); ! 1138: gi.modelindex ("models/monsters/blackwidow/gib2/tris.md2"); ! 1139: gi.modelindex ("models/monsters/blackwidow/gib3/tris.md2"); ! 1140: gi.modelindex ("models/monsters/blackwidow/gib4/tris.md2"); ! 1141: gi.modelindex ("models/monsters/blackwidow2/gib1/tris.md2"); ! 1142: gi.modelindex ("models/monsters/blackwidow2/gib2/tris.md2"); ! 1143: gi.modelindex ("models/monsters/blackwidow2/gib3/tris.md2"); ! 1144: gi.modelindex ("models/monsters/blackwidow2/gib4/tris.md2"); ! 1145: } ! 1146: ! 1147: /*QUAKED monster_widow2 (1 .5 0) (-70 -70 0) (70 70 144) Ambush Trigger_Spawn Sight ! 1148: */ ! 1149: void SP_monster_widow2 (edict_t *self) ! 1150: { ! 1151: if (deathmatch->value) ! 1152: { ! 1153: G_FreeEdict (self); ! 1154: return; ! 1155: } ! 1156: ! 1157: sound_pain1 = gi.soundindex ("bosshovr/bhvpain1.wav"); ! 1158: sound_pain2 = gi.soundindex ("bosshovr/bhvpain2.wav"); ! 1159: sound_pain3 = gi.soundindex ("bosshovr/bhvpain3.wav"); ! 1160: sound_death = gi.soundindex ("bosshovr/bhvdeth1.wav"); ! 1161: sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav"); ! 1162: sound_disrupt = gi.soundindex ("gladiator/railgun.wav"); ! 1163: sound_tentacles_retract = gi.soundindex ("brain/brnatck3.wav"); ! 1164: ! 1165: self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav"); ! 1166: ! 1167: self->movetype = MOVETYPE_STEP; ! 1168: self->solid = SOLID_BBOX; ! 1169: self->s.modelindex = gi.modelindex ("models/monsters/blackwidow2/tris.md2"); ! 1170: VectorSet (self->mins, -70, -70, 0); ! 1171: VectorSet (self->maxs, 70, 70, 144); ! 1172: ! 1173: self->health = 2000 + 1000*(skill->value); ! 1174: if (coop->value) ! 1175: self->health += 500*(skill->value); ! 1176: // self->health = 1; ! 1177: self->gib_health = -900; ! 1178: self->mass = 2500; ! 1179: ! 1180: /* if (skill->value == 2) ! 1181: { ! 1182: self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; ! 1183: self->monsterinfo.power_armor_power = 500; ! 1184: } ! 1185: else */if (skill->value == 3) ! 1186: { ! 1187: self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; ! 1188: self->monsterinfo.power_armor_power = 750; ! 1189: } ! 1190: ! 1191: self->yaw_speed = 30; ! 1192: ! 1193: self->flags |= FL_IMMUNE_LASER; ! 1194: self->monsterinfo.aiflags |= AI_IGNORE_SHOTS; ! 1195: ! 1196: self->pain = widow2_pain; ! 1197: self->die = widow2_die; ! 1198: ! 1199: self->monsterinfo.melee = widow2_melee; ! 1200: self->monsterinfo.stand = widow2_stand; ! 1201: self->monsterinfo.walk = widow2_walk; ! 1202: self->monsterinfo.run = widow2_run; ! 1203: self->monsterinfo.attack = widow2_attack; ! 1204: self->monsterinfo.search = widow2_search; ! 1205: self->monsterinfo.checkattack = Widow2_CheckAttack; ! 1206: gi.linkentity (self); ! 1207: ! 1208: self->monsterinfo.currentmove = &widow2_move_stand; ! 1209: self->monsterinfo.scale = MODEL_SCALE; ! 1210: ! 1211: Widow2Precache(); ! 1212: WidowCalcSlots(self); ! 1213: walkmonster_start (self); ! 1214: } ! 1215: ! 1216: // ! 1217: // Death sequence stuff ! 1218: // ! 1219: ! 1220: void WidowVelocityForDamage (int damage, vec3_t v) ! 1221: { ! 1222: v[0] = damage * crandom(); ! 1223: v[1] = damage * crandom(); ! 1224: v[2] = damage * crandom() + 200.0; ! 1225: } ! 1226: ! 1227: void widow_gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) ! 1228: { ! 1229: ! 1230: self->solid = SOLID_NOT; ! 1231: self->touch = NULL; ! 1232: self->s.angles[PITCH] = 0; ! 1233: self->s.angles[ROLL] = 0; ! 1234: VectorClear (self->avelocity); ! 1235: ! 1236: if (self->plat2flags) ! 1237: gi.sound (self, CHAN_VOICE, self->plat2flags, 1, ATTN_NORM, 0); ! 1238: /* ! 1239: if (plane) ! 1240: { ! 1241: if (plane->normal[2] < -0.8) ! 1242: { ! 1243: gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0); ! 1244: } ! 1245: ! 1246: //vectoangles (plane->normal, normal_angles); ! 1247: //AngleVectors (normal_angles, NULL, right, NULL); ! 1248: //vectoangles (right, self->s.angles); ! 1249: //VectorClear (self->avelocity); ! 1250: } ! 1251: */ ! 1252: } ! 1253: ! 1254: void ThrowWidowGib (edict_t *self, char *gibname, int damage, int type) ! 1255: { ! 1256: ThrowWidowGibReal (self, gibname, damage, type, NULL, false, 0, true); ! 1257: } ! 1258: ! 1259: void ThrowWidowGibLoc (edict_t *self, char *gibname, int damage, int type, vec3_t startpos, qboolean fade) ! 1260: { ! 1261: ThrowWidowGibReal (self, gibname, damage, type, startpos, false, 0, fade); ! 1262: } ! 1263: ! 1264: void ThrowWidowGibSized (edict_t *self, char *gibname, int damage, int type, vec3_t startpos, int hitsound, qboolean fade) ! 1265: { ! 1266: ThrowWidowGibReal (self, gibname, damage, type, startpos, true, hitsound, fade); ! 1267: } ! 1268: ! 1269: void ThrowWidowGibReal (edict_t *self, char *gibname, int damage, int type, vec3_t startpos, qboolean sized, int hitsound, qboolean fade) ! 1270: { ! 1271: edict_t *gib; ! 1272: vec3_t vd; ! 1273: vec3_t origin; ! 1274: vec3_t size; ! 1275: float vscale; ! 1276: ! 1277: if (!gibname) ! 1278: return; ! 1279: ! 1280: gib = G_Spawn(); ! 1281: ! 1282: if (startpos) ! 1283: VectorCopy (startpos, gib->s.origin); ! 1284: else ! 1285: { ! 1286: VectorScale (self->size, 0.5, size); ! 1287: VectorAdd (self->absmin, size, origin); ! 1288: gib->s.origin[0] = origin[0] + crandom() * size[0]; ! 1289: gib->s.origin[1] = origin[1] + crandom() * size[1]; ! 1290: gib->s.origin[2] = origin[2] + crandom() * size[2]; ! 1291: } ! 1292: ! 1293: gib->solid = SOLID_NOT; ! 1294: gib->s.effects |= EF_GIB; ! 1295: gib->flags |= FL_NO_KNOCKBACK; ! 1296: gib->takedamage = DAMAGE_YES; ! 1297: gib->die = gib_die; ! 1298: gib->s.renderfx |= RF_IR_VISIBLE; ! 1299: ! 1300: if (fade) ! 1301: { ! 1302: gib->think = G_FreeEdict; ! 1303: // sized gibs last longer ! 1304: if (sized) ! 1305: gib->nextthink = level.time + 20 + random()*15; ! 1306: else ! 1307: gib->nextthink = level.time + 10 + random()*10; ! 1308: } ! 1309: else ! 1310: { ! 1311: gib->think = G_FreeEdict; ! 1312: // sized gibs last longer ! 1313: if (sized) ! 1314: gib->nextthink = level.time + 60 + random()*15; ! 1315: else ! 1316: gib->nextthink = level.time + 25 + random()*10; ! 1317: } ! 1318: ! 1319: if (type == GIB_ORGANIC) ! 1320: { ! 1321: gib->movetype = MOVETYPE_TOSS; ! 1322: gib->touch = gib_touch; ! 1323: vscale = 0.5; ! 1324: } ! 1325: else ! 1326: { ! 1327: gib->movetype = MOVETYPE_BOUNCE; ! 1328: vscale = 1.0; ! 1329: } ! 1330: ! 1331: WidowVelocityForDamage (damage, vd); ! 1332: VectorMA (self->velocity, vscale, vd, gib->velocity); ! 1333: ClipGibVelocity (gib); ! 1334: ! 1335: gi.setmodel (gib, gibname); ! 1336: ! 1337: if (sized) ! 1338: { ! 1339: gib->plat2flags = hitsound; ! 1340: gib->solid = SOLID_BBOX; ! 1341: gib->avelocity[0] = random()*400; ! 1342: gib->avelocity[1] = random()*400; ! 1343: gib->avelocity[2] = random()*200; ! 1344: if (gib->velocity[2] < 0) ! 1345: gib->velocity[2] *= -1; ! 1346: gib->velocity[2] = max((350 + (random()*100.0)), gib->velocity[2]); ! 1347: gib->gravity = 0.25; ! 1348: gib->touch = widow_gib_touch; ! 1349: gib->owner = self; ! 1350: if (gib->s.modelindex == gi.modelindex ("models/monsters/blackwidow2/gib2/tris.md2")) ! 1351: { ! 1352: VectorSet (gib->mins, -10, -10, 0); ! 1353: VectorSet (gib->maxs, 10, 10, 10); ! 1354: } ! 1355: else ! 1356: { ! 1357: VectorSet (gib->mins, -5, -5, 0); ! 1358: VectorSet (gib->maxs, 5, 5, 5); ! 1359: } ! 1360: } ! 1361: else ! 1362: { ! 1363: gib->velocity[0] *= 2; ! 1364: gib->velocity[1] *= 2; ! 1365: gib->avelocity[0] = random()*600; ! 1366: gib->avelocity[1] = random()*600; ! 1367: gib->avelocity[2] = random()*600; ! 1368: } ! 1369: ! 1370: // gib->think = G_FreeEdict; ! 1371: // gib->nextthink = level.time + 10 + random()*10; ! 1372: ! 1373: gi.linkentity (gib); ! 1374: } ! 1375: ! 1376: void BloodFountain (edict_t *self, int number, vec3_t startpos, int damage) ! 1377: { ! 1378: int n; ! 1379: vec3_t vd; ! 1380: vec3_t origin, size, velocity; ! 1381: ! 1382: return; ! 1383: ! 1384: for (n= 0; n < number; n++) ! 1385: { ! 1386: if (startpos) ! 1387: VectorCopy (startpos, origin); ! 1388: else ! 1389: { ! 1390: VectorScale (self->size, 0.5, size); ! 1391: VectorAdd (self->absmin, size, origin); ! 1392: origin[0] = origin[0] + crandom() * size[0]; ! 1393: origin[1] = origin[1] + crandom() * size[1]; ! 1394: origin[2] = origin[2] + crandom() * size[2]; ! 1395: } ! 1396: ! 1397: WidowVelocityForDamage (damage, vd); ! 1398: VectorMA (self->velocity, 1.0, vd, velocity); ! 1399: velocity[0] *= 2; ! 1400: velocity[1] *= 2; ! 1401: ! 1402: // gi.WriteByte (svc_temp_entity); ! 1403: // gi.WriteByte (TE_BLOOD_FOUNTAIN); ! 1404: // gi.WritePosition (origin); ! 1405: // gi.WritePosition (velocity); ! 1406: // gi.WriteShort (50); ! 1407: // gi.multicast (self->s.origin, MULTICAST_ALL); ! 1408: } ! 1409: } ! 1410: ! 1411: void ThrowSmallStuff (edict_t *self, vec3_t point) ! 1412: { ! 1413: int n; ! 1414: ! 1415: for (n= 0; n < 2; n++) ! 1416: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, point, false); ! 1417: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, point, false); ! 1418: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 150, GIB_METALLIC, point, false); ! 1419: ! 1420: } ! 1421: ! 1422: void ThrowMoreStuff (edict_t *self, vec3_t point) ! 1423: { ! 1424: int n; ! 1425: ! 1426: if (coop && coop->value) ! 1427: { ! 1428: ThrowSmallStuff (self, point); ! 1429: return; ! 1430: } ! 1431: ! 1432: for (n= 0; n < 2; n++) ! 1433: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, point, false); ! 1434: for (n= 0; n < 2; n++) ! 1435: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, point, false); ! 1436: for (n= 0; n < 3; n++) ! 1437: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, point, false); ! 1438: ! 1439: } ! 1440: ! 1441: void WidowExplode (edict_t *self) ! 1442: { ! 1443: vec3_t org; ! 1444: int n; ! 1445: ! 1446: self->think = WidowExplode; ! 1447: // gi.dprintf ("count = %d\n"); ! 1448: ! 1449: redo: ! 1450: VectorCopy (self->s.origin, org); ! 1451: org[2] += 24 + (rand()&15); ! 1452: if (self->count < 8) ! 1453: org[2] += 24 + (rand()&31); ! 1454: switch (self->count) ! 1455: { ! 1456: case 0: ! 1457: org[0] -= 24; ! 1458: org[1] -= 24; ! 1459: break; ! 1460: case 1: ! 1461: org[0] += 24; ! 1462: org[1] += 24; ! 1463: ThrowSmallStuff(self, org); ! 1464: break; ! 1465: case 2: ! 1466: org[0] += 24; ! 1467: org[1] -= 24; ! 1468: break; ! 1469: case 3: ! 1470: org[0] -= 24; ! 1471: org[1] += 24; ! 1472: ThrowMoreStuff(self, org); ! 1473: break; ! 1474: case 4: ! 1475: org[0] -= 48; ! 1476: org[1] -= 48; ! 1477: break; ! 1478: case 5: ! 1479: org[0] += 48; ! 1480: org[1] += 48; ! 1481: ThrowArm1 (self); ! 1482: break; ! 1483: case 6: ! 1484: org[0] -= 48; ! 1485: org[1] += 48; ! 1486: ThrowArm2 (self); ! 1487: break; ! 1488: case 7: ! 1489: org[0] += 48; ! 1490: org[1] -= 48; ! 1491: ThrowSmallStuff(self, org); ! 1492: break; ! 1493: case 8: ! 1494: org[0] += 18; ! 1495: org[1] += 18; ! 1496: org[2] = self->s.origin[2] + 48; ! 1497: ThrowMoreStuff(self, org); ! 1498: break; ! 1499: case 9: ! 1500: org[0] -= 18; ! 1501: org[1] += 18; ! 1502: org[2] = self->s.origin[2] + 48; ! 1503: break; ! 1504: case 10: ! 1505: org[0] += 18; ! 1506: org[1] -= 18; ! 1507: org[2] = self->s.origin[2] + 48; ! 1508: break; ! 1509: case 11: ! 1510: org[0] -= 18; ! 1511: org[1] -= 18; ! 1512: org[2] = self->s.origin[2] + 48; ! 1513: break; ! 1514: case 12: ! 1515: self->s.sound = 0; ! 1516: for (n= 0; n < 2; n++) ! 1517: ThrowWidowGib (self, "models/objects/gibs/sm_meat/tris.md2", 400, GIB_ORGANIC); ! 1518: for (n= 0; n < 2; n++) ! 1519: ThrowWidowGib (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC); ! 1520: for (n= 0; n < 2; n++) ! 1521: ThrowWidowGib (self, "models/objects/gibs/sm_metal/tris.md2", 400, GIB_METALLIC); ! 1522: // ThrowGib (self, "models/objects/gibs/chest/tris.md2", 1000, GIB_ORGANIC); ! 1523: // ThrowHead (self, "models/objects/gibs/gear/tris.md2", 1000, GIB_METALLIC); ! 1524: self->deadflag = DEAD_DEAD; ! 1525: self->think = monster_think; ! 1526: self->nextthink = level.time + 0.1; ! 1527: self->monsterinfo.currentmove = &widow2_move_dead; ! 1528: return; ! 1529: } ! 1530: ! 1531: self->count++; ! 1532: if (self->count >=9 && self->count <=12) ! 1533: { ! 1534: gi.WriteByte (svc_temp_entity); ! 1535: gi.WriteByte (TE_EXPLOSION1_BIG); ! 1536: gi.WritePosition (org); ! 1537: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1538: goto redo; ! 1539: } ! 1540: // else ! 1541: gi.WriteByte (svc_temp_entity); ! 1542: if (self->count %2) ! 1543: gi.WriteByte (TE_EXPLOSION1); ! 1544: else ! 1545: gi.WriteByte (TE_EXPLOSION1_NP); ! 1546: gi.WritePosition (org); ! 1547: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1548: ! 1549: self->nextthink = level.time + 0.1; ! 1550: } ! 1551: ! 1552: void WidowExplosion1 (edict_t *self) ! 1553: { ! 1554: int n; ! 1555: vec3_t f,r,u, startpoint; ! 1556: vec3_t offset = {23.74, -37.67, 76.96}; ! 1557: ! 1558: // gi.dprintf ("1\n"); ! 1559: AngleVectors (self->s.angles, f, r, u); ! 1560: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 1561: ! 1562: gi.WriteByte (svc_temp_entity); ! 1563: gi.WriteByte (TE_EXPLOSION1); ! 1564: gi.WritePosition (startpoint); ! 1565: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1566: ! 1567: for (n= 0; n < 2; n++) ! 1568: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1569: for (n= 0; n < 2; n++) ! 1570: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1571: for (n= 0; n < 2; n++) ! 1572: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); ! 1573: } ! 1574: ! 1575: void WidowExplosion2 (edict_t *self) ! 1576: { ! 1577: int n; ! 1578: vec3_t f,r,u, startpoint; ! 1579: vec3_t offset = {-20.49, 36.92, 73.52}; ! 1580: ! 1581: // gi.dprintf ("2\n"); ! 1582: ! 1583: AngleVectors (self->s.angles, f, r, u); ! 1584: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 1585: ! 1586: gi.WriteByte (svc_temp_entity); ! 1587: gi.WriteByte (TE_EXPLOSION1); ! 1588: gi.WritePosition (startpoint); ! 1589: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1590: ! 1591: for (n= 0; n < 2; n++) ! 1592: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1593: for (n= 0; n < 2; n++) ! 1594: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1595: for (n= 0; n < 2; n++) ! 1596: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); ! 1597: } ! 1598: ! 1599: void WidowExplosion3 (edict_t *self) ! 1600: { ! 1601: int n; ! 1602: vec3_t f,r,u, startpoint; ! 1603: vec3_t offset = {2.11, 0.05, 92.20}; ! 1604: ! 1605: // gi.dprintf ("3\n"); ! 1606: ! 1607: AngleVectors (self->s.angles, f, r, u); ! 1608: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 1609: ! 1610: gi.WriteByte (svc_temp_entity); ! 1611: gi.WriteByte (TE_EXPLOSION1); ! 1612: gi.WritePosition (startpoint); ! 1613: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1614: ! 1615: for (n= 0; n < 2; n++) ! 1616: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1617: for (n= 0; n < 2; n++) ! 1618: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1619: for (n= 0; n < 2; n++) ! 1620: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); ! 1621: } ! 1622: ! 1623: void WidowExplosion4 (edict_t *self) ! 1624: { ! 1625: int n; ! 1626: vec3_t f,r,u, startpoint; ! 1627: vec3_t offset = {-28.04, -35.57, -77.56}; ! 1628: ! 1629: // gi.dprintf ("4\n"); ! 1630: ! 1631: AngleVectors (self->s.angles, f, r, u); ! 1632: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 1633: ! 1634: gi.WriteByte (svc_temp_entity); ! 1635: gi.WriteByte (TE_EXPLOSION1); ! 1636: gi.WritePosition (startpoint); ! 1637: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1638: ! 1639: for (n= 0; n < 2; n++) ! 1640: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1641: for (n= 0; n < 2; n++) ! 1642: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1643: for (n= 0; n < 2; n++) ! 1644: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); ! 1645: } ! 1646: ! 1647: void WidowExplosion5 (edict_t *self) ! 1648: { ! 1649: int n; ! 1650: vec3_t f,r,u, startpoint; ! 1651: vec3_t offset = {-20.11, -1.11, 40.76}; ! 1652: ! 1653: // gi.dprintf ("5\n"); ! 1654: ! 1655: AngleVectors (self->s.angles, f, r, u); ! 1656: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 1657: ! 1658: gi.WriteByte (svc_temp_entity); ! 1659: gi.WriteByte (TE_EXPLOSION1); ! 1660: gi.WritePosition (startpoint); ! 1661: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1662: ! 1663: for (n= 0; n < 2; n++) ! 1664: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1665: for (n= 0; n < 2; n++) ! 1666: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1667: for (n= 0; n < 2; n++) ! 1668: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); ! 1669: } ! 1670: ! 1671: void WidowExplosion6 (edict_t *self) ! 1672: { ! 1673: int n; ! 1674: vec3_t f,r,u, startpoint; ! 1675: vec3_t offset = {-20.11, -1.11, 40.76}; ! 1676: ! 1677: //gi.dprintf ("6\n"); ! 1678: ! 1679: AngleVectors (self->s.angles, f, r, u); ! 1680: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 1681: ! 1682: gi.WriteByte (svc_temp_entity); ! 1683: gi.WriteByte (TE_EXPLOSION1); ! 1684: gi.WritePosition (startpoint); ! 1685: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1686: ! 1687: for (n= 0; n < 2; n++) ! 1688: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1689: for (n= 0; n < 2; n++) ! 1690: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1691: for (n= 0; n < 2; n++) ! 1692: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); ! 1693: } ! 1694: ! 1695: void WidowExplosion7 (edict_t *self) ! 1696: { ! 1697: int n; ! 1698: vec3_t f,r,u, startpoint; ! 1699: vec3_t offset = {-20.11, -1.11, 40.76}; ! 1700: ! 1701: //gi.dprintf ("7\n"); ! 1702: ! 1703: AngleVectors (self->s.angles, f, r, u); ! 1704: G_ProjectSource2 (self->s.origin, offset, f, r, u, startpoint); ! 1705: ! 1706: gi.WriteByte (svc_temp_entity); ! 1707: gi.WriteByte (TE_EXPLOSION1); ! 1708: gi.WritePosition (startpoint); ! 1709: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1710: ! 1711: for (n= 0; n < 2; n++) ! 1712: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1713: for (n= 0; n < 2; n++) ! 1714: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1715: for (n= 0; n < 2; n++) ! 1716: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 300, GIB_METALLIC, startpoint, false); ! 1717: } ! 1718: ! 1719: void WidowExplosionLeg (edict_t *self) ! 1720: { ! 1721: int n; ! 1722: vec3_t f,r,u, startpoint; ! 1723: vec3_t offset1 = {-31.89, -47.86, 67.02}; ! 1724: vec3_t offset2 = {-44.9, -82.14, 54.72}; ! 1725: ! 1726: //gi.dprintf ("Leg\n"); ! 1727: ! 1728: AngleVectors (self->s.angles, f, r, u); ! 1729: G_ProjectSource2 (self->s.origin, offset1, f, r, u, startpoint); ! 1730: ! 1731: gi.WriteByte (svc_temp_entity); ! 1732: gi.WriteByte (TE_EXPLOSION1_BIG); ! 1733: gi.WritePosition (startpoint); ! 1734: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1735: ! 1736: ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib2/tris.md2", 200, GIB_METALLIC, startpoint, ! 1737: gi.soundindex ("misc/fhit3.wav"), false); ! 1738: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1739: for (n= 0; n < 2; n++) ! 1740: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1741: ! 1742: G_ProjectSource2 (self->s.origin, offset2, f, r, u, startpoint); ! 1743: ! 1744: gi.WriteByte (svc_temp_entity); ! 1745: gi.WriteByte (TE_EXPLOSION1); ! 1746: gi.WritePosition (startpoint); ! 1747: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1748: ! 1749: ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib1/tris.md2", 300, GIB_METALLIC, startpoint, ! 1750: gi.soundindex ("misc/fhit3.wav"), false); ! 1751: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1752: for (n= 0; n < 2; n++) ! 1753: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1754: } ! 1755: ! 1756: void ThrowArm1 (edict_t *self) ! 1757: { ! 1758: int n; ! 1759: vec3_t f,r,u, startpoint; ! 1760: vec3_t offset1 = {65.76, 17.52, 7.56}; ! 1761: ! 1762: AngleVectors (self->s.angles, f, r, u); ! 1763: G_ProjectSource2 (self->s.origin, offset1, f, r, u, startpoint); ! 1764: ! 1765: gi.WriteByte (svc_temp_entity); ! 1766: gi.WriteByte (TE_EXPLOSION1_BIG); ! 1767: gi.WritePosition (startpoint); ! 1768: gi.multicast (self->s.origin, MULTICAST_ALL); ! 1769: ! 1770: for (n= 0; n < 2; n++) ! 1771: ThrowWidowGibLoc (self, "models/objects/gibs/sm_metal/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1772: } ! 1773: ! 1774: void ThrowArm2 (edict_t *self) ! 1775: { ! 1776: int n; ! 1777: vec3_t f,r,u, startpoint; ! 1778: vec3_t offset1 = {65.76, 17.52, 7.56}; ! 1779: ! 1780: AngleVectors (self->s.angles, f, r, u); ! 1781: G_ProjectSource2 (self->s.origin, offset1, f, r, u, startpoint); ! 1782: ! 1783: ThrowWidowGibSized (self, "models/monsters/blackwidow2/gib4/tris.md2", 200, GIB_METALLIC, startpoint, ! 1784: gi.soundindex ("misc/fhit3.wav"), false); ! 1785: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 300, GIB_ORGANIC, startpoint, false); ! 1786: for (n= 0; n < 2; n++) ! 1787: ThrowWidowGibLoc (self, "models/objects/gibs/sm_meat/tris.md2", 100, GIB_METALLIC, startpoint, false); ! 1788: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.