Annotation of quake2/rogue/m_widow2.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.