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

1.1       root        1: /*
                      2: ==============================================================================
                      3: 
                      4: carrier
                      5: 
                      6: ==============================================================================
                      7: */
                      8: 
                      9: // self->timestamp used for frame calculations in grenade & spawn code
                     10: // self->wait used to prevent rapid refire of rocket launcher
                     11: 
                     12: #include "g_local.h"
                     13: #include "m_carrier.h"
                     14: 
                     15: #define        CARRIER_ROCKET_TIME             2               // number of seconds between rocket shots
                     16: #define CARRIER_ROCKET_SPEED   750
                     17: #define        NUM_FLYERS_SPAWNED              6               // max # of flyers he can spawn
                     18: 
                     19: #define        RAIL_FIRE_TIME                  3
                     20: 
                     21: void BossExplode (edict_t *self);
                     22: void Grenade_Explode (edict_t *ent);
                     23: 
                     24: qboolean infront (edict_t *self, edict_t *other);
                     25: qboolean inback (edict_t *self, edict_t *other);
                     26: qboolean below (edict_t *self, edict_t *other);
                     27: void drawbbox (edict_t *self);
                     28: 
                     29: //char *ED_NewString (char *string);
                     30: void ED_CallSpawn (edict_t *ent);
                     31: 
                     32: static int     sound_pain1;
                     33: static int     sound_pain2;
                     34: static int     sound_pain3;
                     35: static int     sound_death;
                     36: static int     sound_search1;
                     37: static int     sound_rail;
                     38: 
                     39: float  orig_yaw_speed;
                     40: 
                     41: vec3_t flyer_mins = {-16, -16, -24};
                     42: vec3_t flyer_maxs = {16, 16, 16};
                     43: 
                     44: extern mmove_t flyer_move_attack2, flyer_move_attack3, flyer_move_kamikaze;
                     45: 
                     46: 
                     47: void carrier_run (edict_t *self);
                     48: void carrier_stand (edict_t *self);
                     49: void carrier_dead (edict_t *self);
                     50: void carrier_attack (edict_t *self);
                     51: void carrier_attack_mg (edict_t *self);
                     52: void carrier_reattack_mg (edict_t *self);
                     53: void carrier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
                     54: 
                     55: void carrier_attack_gren (edict_t *self);
                     56: void carrier_reattack_gren (edict_t *self);
                     57: 
                     58: void carrier_start_spawn (edict_t *self);
                     59: void carrier_spawn_check (edict_t *self);
                     60: void carrier_prep_spawn (edict_t *self);
                     61: 
                     62: void CarrierMachineGunHold (edict_t *self);
                     63: void CarrierRocket (edict_t *self);
                     64: 
                     65: 
                     66: 
                     67: // code starts here
                     68: void carrier_search (edict_t *self)
                     69: {
                     70:        if (random() < 0.5)
                     71:                gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0);
                     72: }
                     73: 
                     74: //
                     75: // this is the smarts for the rocket launcher in coop
                     76: //
                     77: // if there is a player behind/below the carrier, and we can shoot, and we can trace a LOS to them ..
                     78: // pick one of the group, and let it rip
                     79: void CarrierCoopCheck (edict_t *self)
                     80: {
                     81:        // no more than 4 players in coop, so..
                     82:        edict_t *targets[4];
                     83:        int             num_targets = 0, target, player;
                     84:        edict_t *ent;
                     85:        trace_t tr;
                     86: 
                     87:        // if we're not in coop, this is a noop
                     88:        if (!coop || !coop->value)
                     89:                return;
                     90:        // if we are, and we have recently fired, bail
                     91:        if (self->wait > level.time)
                     92:                return;
                     93: 
                     94:        memset (targets, 0, 4*sizeof(edict_t *));
                     95: 
                     96:        // cycle through players
                     97:        for (player = 1; player <= game.maxclients; player++)
                     98:        {
                     99:                ent = &g_edicts[player];
                    100:                if (!ent->inuse)
                    101:                        continue;
                    102:                if (!ent->client)
                    103:                        continue;
                    104:                if (inback(self, ent) || below(self, ent))
                    105:                {
                    106:                        tr = gi.trace (self->s.origin, NULL, NULL, ent->s.origin, self, MASK_SOLID);
                    107:                        if (tr.fraction == 1.0)
                    108:                        {
                    109:                                if ((g_showlogic) && (g_showlogic->value))
                    110:                                        gi.dprintf ("Carrier: found a player who I can shoot\n");
                    111:                                targets[num_targets++] = ent;
                    112:                        }
                    113:                }
                    114:        }
                    115: 
                    116:        if (!num_targets)
                    117:                return;
                    118: 
                    119:        // get a number from 0 to (num_targets-1)
                    120:        target = random() * num_targets;
                    121:        
                    122:        // just in case we got a 1.0 from random
                    123:        if (target == num_targets)
                    124:                target--;
                    125: 
                    126:        // make sure to prevent rapid fire rockets
                    127:        self->wait = level.time + CARRIER_ROCKET_TIME;
                    128: 
                    129:        // save off the real enemy
                    130:        ent = self->enemy;
                    131:        // set the new guy as temporary enemy
                    132:        self->enemy = targets[target];
                    133:        CarrierRocket (self);
                    134:        // put the real enemy back
                    135:        self->enemy = ent;
                    136: 
                    137:        // we're done
                    138:        return;
                    139: }
                    140: 
                    141: void CarrierGrenade (edict_t *self)
                    142: {
                    143:        vec3_t  start;
                    144:        vec3_t  forward, right, up;
                    145:        vec3_t  aim;
                    146:        int             flash_number;
                    147:        float   direction;              // from lower left to upper right, or lower right to upper left
                    148:        float   spreadR, spreadU;
                    149:        int             mytime;
                    150: 
                    151:        CarrierCoopCheck(self);
                    152: 
                    153:        if (!self->enemy)
                    154:                return;
                    155: 
                    156:        if (random() < 0.5)
                    157:                direction = -1.0;
                    158:        else
                    159:                direction = 1.0;
                    160: 
                    161:        mytime = (int)((level.time - self->timestamp)/0.4);
                    162: 
                    163:        if (mytime == 0)
                    164:        {
                    165:                spreadR = 0.15 * direction;
                    166: //             spreadU = 0.1 * direction;
                    167:                spreadU = 0.1 - 0.1 * direction;
                    168:        }
                    169:        else if (mytime == 1)
                    170:        {
                    171:                spreadR = 0;
                    172: //             spreadU = 0;
                    173:                spreadU = 0.1;
                    174:        }
                    175:        else if (mytime == 2)
                    176:        {
                    177:                spreadR = -0.15 * direction;
                    178: //             spreadU = -0.1 * direction;
                    179:                spreadU = 0.1 - -0.1 * direction;
                    180:        }
                    181:        else if (mytime == 3)
                    182:        {
                    183:                spreadR = 0;
                    184: //             spreadU = 0;
                    185:                spreadU = 0.1;
                    186:        }
                    187:        else
                    188:        {
                    189:                // error, shoot straight
                    190:                if ((g_showlogic) && (g_showlogic->value))
                    191:                        gi.dprintf ("CarrierGrenade: bad time  %2.2f   %2.2f\n", level.time, self->timestamp);
                    192:                spreadR = 0;
                    193:                spreadU = 0;
                    194:        }
                    195: 
                    196:        AngleVectors (self->s.angles, forward, right, up);
                    197:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_GRENADE], forward, right, start);
                    198: 
                    199:        VectorSubtract (self->enemy->s.origin, start, aim);
                    200:        VectorNormalize (aim);
                    201: 
                    202:        VectorMA (aim, spreadR, right, aim);
                    203:        VectorMA (aim, spreadU, up, aim);
                    204: 
                    205:        if(aim[2] > 0.15)
                    206:                aim[2] = 0.15;
                    207:        else if(aim[2] < -0.5)
                    208:                aim[2] = -0.5;
                    209: 
                    210:        flash_number = MZ2_GUNNER_GRENADE_1;
                    211:        monster_fire_grenade (self, start, aim, 50, 600, flash_number);
                    212: }
                    213: 
                    214: void CarrierPredictiveRocket  (edict_t *self)
                    215: {
                    216:        vec3_t  forward, right;
                    217:        vec3_t  start;
                    218:        vec3_t  dir;
                    219: 
                    220: //     if ((g_showlogic) && (g_showlogic->value))
                    221: //             gi.dprintf("predictive fire\n");
                    222: 
                    223:        AngleVectors (self->s.angles, forward, right, NULL);
                    224: 
                    225: //1
                    226:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_1], forward, right, start);
                    227:        PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, -0.3, dir, NULL);
                    228:        monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_1);
                    229: 
                    230: //2
                    231:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_2], forward, right, start);
                    232:        PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, -0.15, dir, NULL);
                    233:        monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_2);
                    234: 
                    235: //3
                    236:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_3], forward, right, start);
                    237:        PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, 0, dir, NULL);
                    238:        monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_3);
                    239: 
                    240: //4
                    241:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_4], forward, right, start);
                    242:        PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, 0.15, dir, NULL);
                    243:        monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_4);
                    244: }      
                    245: 
                    246: void CarrierRocket (edict_t *self)
                    247: {
                    248:        vec3_t  forward, right;
                    249:        vec3_t  start;
                    250:        vec3_t  dir;
                    251:        vec3_t  vec;
                    252: 
                    253:        if(self->enemy)
                    254:        {
                    255:                if(self->enemy->client && random() < 0.5)
                    256:                {
                    257:                        CarrierPredictiveRocket(self);
                    258:                        return;
                    259:                }
                    260:        }
                    261:        else
                    262:                return;
                    263: 
                    264:        AngleVectors (self->s.angles, forward, right, NULL);
                    265: 
                    266: //1
                    267:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_1], forward, right, start);
                    268:        VectorCopy (self->enemy->s.origin, vec);
                    269: //     vec[2] += self->enemy->viewheight;
                    270:        vec[2] -= 15;
                    271:        VectorSubtract (vec, start, dir);
                    272:        VectorNormalize (dir);
                    273:        VectorMA (dir, 0.4, right, dir);
                    274:        VectorNormalize (dir);
                    275:        monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_1);
                    276: 
                    277: //2
                    278:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_2], forward, right, start);
                    279:        VectorCopy (self->enemy->s.origin, vec);
                    280: //     vec[2] += self->enemy->viewheight;
                    281:        VectorSubtract (vec, start, dir);
                    282:        VectorNormalize (dir);
                    283:        VectorMA (dir, 0.025, right, dir);
                    284:        VectorNormalize (dir);
                    285:        monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_2);
                    286: 
                    287: //3
                    288:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_3], forward, right, start);
                    289:        VectorCopy (self->enemy->s.origin, vec);
                    290: //     vec[2] += self->enemy->viewheight;
                    291:        VectorSubtract (vec, start, dir);
                    292:        VectorNormalize (dir);
                    293:        VectorMA (dir, -0.025, right, dir);
                    294:        VectorNormalize (dir);
                    295:        monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_3);
                    296: 
                    297: //4
                    298:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_4], forward, right, start);
                    299:        VectorCopy (self->enemy->s.origin, vec);
                    300: //     vec[2] += self->enemy->viewheight;
                    301:        vec[2] -= 15;
                    302:        VectorSubtract (vec, start, dir);
                    303:        VectorNormalize (dir);
                    304:        VectorMA (dir, -0.4, right, dir);
                    305:        VectorNormalize (dir);
                    306:        monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_4);
                    307: 
                    308: //5
                    309: //     G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
                    310: //     VectorCopy (self->enemy->s.origin, vec);
                    311: //     vec[2] += self->enemy->viewheight;
                    312: //     VectorSubtract (vec, start, dir);
                    313: //     VectorNormalize (dir);
                    314: //     monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
                    315: }      
                    316: 
                    317: void carrier_firebullet_right (edict_t *self)
                    318: {
                    319:        vec3_t  forward, right, target;
                    320:        vec3_t  start;
                    321:        int             flashnum;
                    322: 
                    323:        // if we're in manual steering mode, it means we're leaning down .. use the lower shot
                    324:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
                    325:                flashnum = MZ2_CARRIER_MACHINEGUN_R2;
                    326:        else
                    327:                flashnum = MZ2_CARRIER_MACHINEGUN_R1;
                    328: 
                    329:        AngleVectors (self->s.angles, forward, right, NULL);
                    330:        G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start);
                    331: 
                    332: //     VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
                    333:        VectorMA (self->enemy->s.origin, 0.2, self->enemy->velocity, target);
                    334:        target[2] += self->enemy->viewheight;
                    335: /*
                    336:                        gi.WriteByte (svc_temp_entity);
                    337:                        gi.WriteByte (TE_DEBUGTRAIL);
                    338:                        gi.WritePosition (start);
                    339:                        gi.WritePosition (target);
                    340:                        gi.multicast (start, MULTICAST_ALL);    
                    341: */
                    342:        VectorSubtract (target, start, forward);
                    343:        VectorNormalize (forward);
                    344: 
                    345:        monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD*3, DEFAULT_BULLET_VSPREAD, flashnum);
                    346: }      
                    347: 
                    348: void carrier_firebullet_left (edict_t *self)
                    349: {
                    350:        vec3_t  forward, right, target;
                    351:        vec3_t  start;
                    352:        int             flashnum;
                    353: 
                    354:        // if we're in manual steering mode, it means we're leaning down .. use the lower shot
                    355:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
                    356:                flashnum = MZ2_CARRIER_MACHINEGUN_L2;
                    357:        else
                    358:                flashnum = MZ2_CARRIER_MACHINEGUN_L1;
                    359:        
                    360:        AngleVectors (self->s.angles, forward, right, NULL);
                    361:        G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start);
                    362: 
                    363: //     VectorMA (self->enemy->s.origin, 0.2, self->enemy->velocity, target);
                    364:        VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
                    365: 
                    366:        target[2] += self->enemy->viewheight;
                    367:        VectorSubtract (target, start, forward);
                    368: /*
                    369:                        gi.WriteByte (svc_temp_entity);
                    370:                        gi.WriteByte (TE_DEBUGTRAIL);
                    371:                        gi.WritePosition (start);
                    372:                        gi.WritePosition (target);
                    373:                        gi.multicast (start, MULTICAST_ALL);    
                    374: */
                    375:        VectorNormalize (forward);
                    376: 
                    377:        monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD*3, DEFAULT_BULLET_VSPREAD, flashnum);
                    378: }      
                    379: 
                    380: void CarrierMachineGun (edict_t *self)
                    381: {
                    382:        CarrierCoopCheck(self);
                    383:        if (self->enemy)
                    384:                carrier_firebullet_left(self);
                    385:        if (self->enemy)
                    386:                carrier_firebullet_right(self);
                    387: }      
                    388: 
                    389: void CarrierSpawn (edict_t *self)
                    390: {
                    391:        vec3_t  f, r, offset, startpoint, spawnpoint;
                    392:        edict_t *ent;
                    393:        int             mytime;
                    394: 
                    395: //     VectorSet (offset, 105, 0, -30); // real distance needed is (sqrt (56*56*2) + sqrt(16*16*2)) or 101.8
                    396:        VectorSet (offset, 105, 0, -58); // real distance needed is (sqrt (56*56*2) + sqrt(16*16*2)) or 101.8
                    397:        AngleVectors (self->s.angles, f, r, NULL);
                    398: 
                    399:        G_ProjectSource (self->s.origin, offset, f, r, startpoint);
                    400: 
                    401:        // the +0.1 is because level.time is sometimes a little low
                    402:        mytime = (int)((level.time + 0.1 - self->timestamp)/0.5);
                    403:        if ((g_showlogic) && (g_showlogic->value))
                    404:                gi.dprintf ("mytime = %d, (%2.2f)\n", mytime, level.time - self->timestamp);
                    405: 
                    406:        if (FindSpawnPoint (startpoint, flyer_mins, flyer_maxs, spawnpoint, 32))
                    407:        {
                    408:                // the second flier should be a kamikaze flyer
                    409:                if (mytime != 2)
                    410:                        ent = CreateMonster (spawnpoint, self->s.angles, "monster_flyer");
                    411:                else
                    412:                        ent = CreateMonster (spawnpoint, self->s.angles, "monster_kamikaze");
                    413: 
                    414:                if (!ent)
                    415:                        return;
                    416: 
                    417:                self->monsterinfo.monster_slots--;
                    418:        //      if ((g_showlogic) && (g_showlogic->value))
                    419:        //              gi.dprintf ("carrier: post-spawn : %d slots left\n", carrier_monster_slots);
                    420: 
                    421:                ent->nextthink = level.time;
                    422:                ent->think (ent);
                    423:                
                    424:                ent->monsterinfo.aiflags |= AI_SPAWNED_CARRIER|AI_DO_NOT_COUNT|AI_IGNORE_SHOTS;
                    425: 
                    426:                if ((self->enemy->inuse) && (self->enemy->health > 0))
                    427:                {
                    428:                        ent->enemy = self->enemy;
                    429:                        FoundTarget (ent);
                    430:                        if (mytime == 1)
                    431:                        {
                    432:                                ent->monsterinfo.lefty = 0;
                    433:                                ent->monsterinfo.attack_state = AS_SLIDING;
                    434:                                ent->monsterinfo.currentmove = &flyer_move_attack3;
                    435:                        }
                    436:                        else if (mytime == 2)
                    437:                        {
                    438:                                ent->monsterinfo.lefty = 0;
                    439:                                ent->monsterinfo.attack_state = AS_STRAIGHT;
                    440:                                ent->monsterinfo.currentmove = &flyer_move_kamikaze;
                    441:                                ent->mass = 100;
                    442:                                ent->monsterinfo.aiflags |= AI_CHARGING;
                    443:                        }
                    444:                        else if (mytime == 3)
                    445:                        {
                    446:                                ent->monsterinfo.lefty = 1;
                    447:                                ent->monsterinfo.attack_state = AS_SLIDING;
                    448:                                ent->monsterinfo.currentmove = &flyer_move_attack3;
                    449:                        }
                    450:                        else if ((g_showlogic) && (g_showlogic->value))
                    451:                                gi.dprintf ("carrier:  unexpected time %d!\n", mytime);
                    452:                }
                    453:        }
                    454: }
                    455: 
                    456: void carrier_prep_spawn (edict_t *self)
                    457: {
                    458:        CarrierCoopCheck(self);
                    459:        self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
                    460:        self->timestamp = level.time;
                    461:        self->yaw_speed = 10;
                    462:        CarrierMachineGun(self);
                    463: }
                    464: 
                    465: void carrier_spawn_check (edict_t *self)
                    466: {
                    467: //     gi.dprintf ("times - %2.2f %2.2f\n", level.time, self->timestamp);
                    468:        CarrierCoopCheck(self);
                    469:        CarrierMachineGun(self);
                    470:        CarrierSpawn (self);
                    471: 
                    472:        if (level.time > (self->timestamp + 1.1))  // 0.5 seconds per flyer.  this gets three
                    473:        {
                    474:                self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
                    475:                self->yaw_speed = orig_yaw_speed;
                    476:                return;
                    477:        }
                    478:        else
                    479:                self->monsterinfo.nextframe = FRAME_spawn08;
                    480: }
                    481: 
                    482: void carrier_ready_spawn (edict_t *self)
                    483: {
                    484:        float   current_yaw;
                    485:        vec3_t  offset, f, r, startpoint, spawnpoint;
                    486: 
                    487:        CarrierCoopCheck(self);
                    488:        CarrierMachineGun(self);
                    489: 
                    490:        current_yaw = anglemod(self->s.angles[YAW]);
                    491: 
                    492: //     gi.dprintf ("yaws = %2.2f %2.2f\n", current_yaw, self->ideal_yaw);
                    493: 
                    494:        if (fabs(current_yaw - self->ideal_yaw) > 0.1)
                    495:        {
                    496:                self->monsterinfo.aiflags |= AI_HOLD_FRAME;
                    497:                self->timestamp += FRAMETIME;
                    498:                return;
                    499:        }
                    500: 
                    501:        self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
                    502: 
                    503:        VectorSet (offset, 105,0,-58);
                    504:        AngleVectors (self->s.angles, f, r, NULL);
                    505:        G_ProjectSource (self->s.origin, offset, f, r, startpoint);
                    506:        if (FindSpawnPoint (startpoint, flyer_mins, flyer_maxs, spawnpoint, 32))
                    507:        {
                    508:                SpawnGrow_Spawn (spawnpoint, 0);
                    509:        }
                    510: }
                    511: 
                    512: void carrier_start_spawn (edict_t *self)
                    513: {
                    514:        int             mytime;
                    515:        float   enemy_yaw;
                    516:        vec3_t  temp;
                    517: //     vec3_t  offset, f, r, startpoint;
                    518: 
                    519:        CarrierCoopCheck(self);
                    520:        if (!orig_yaw_speed)
                    521:                orig_yaw_speed = self->yaw_speed;
                    522: 
                    523:        if (!self->enemy)
                    524:                return;
                    525: 
                    526:        mytime = (int)((level.time - self->timestamp)/0.5);
                    527: 
                    528:        VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
                    529:        enemy_yaw = vectoyaw2(temp);
                    530: 
                    531:        // note that the offsets are based on a forward of 105 from the end angle
                    532:        if (mytime == 0)
                    533:        {
                    534:                self->ideal_yaw = anglemod(enemy_yaw - 30);
                    535: //             VectorSet (offset, 90.9, 52.5, 0);
                    536:        }
                    537:        else if (mytime == 1)
                    538:        {
                    539:                self->ideal_yaw = anglemod(enemy_yaw);
                    540: //             VectorSet (offset, 90.9, -52.5, 0);
                    541:        }
                    542:        else if (mytime == 2)
                    543:        {
                    544:                self->ideal_yaw = anglemod(enemy_yaw + 30);
                    545: //             VectorSet (offset, 90.9, -52.5, 0);
                    546:        }
                    547:        else if ((g_showlogic) && (g_showlogic->value))
                    548:                gi.dprintf ("carrier: bad spawntime\n");
                    549: 
                    550:        CarrierMachineGun (self);
                    551: }
                    552: 
                    553: mframe_t carrier_frames_stand [] =
                    554: {
                    555: //     ai_stand, 0, drawbbox,
                    556:        ai_stand, 0, NULL,
                    557:        ai_stand, 0, NULL,
                    558:        ai_stand, 0, NULL,
                    559:        ai_stand, 0, NULL,
                    560:        ai_stand, 0, NULL,
                    561:        ai_stand, 0, NULL,
                    562:        ai_stand, 0, NULL,
                    563:        ai_stand, 0, NULL,
                    564:        ai_stand, 0, NULL,
                    565:        ai_stand, 0, NULL,
                    566:        ai_stand, 0, NULL,
                    567:        ai_stand, 0, NULL,
                    568:        ai_stand, 0, NULL
                    569: };
                    570: mmove_t        carrier_move_stand = {FRAME_search01, FRAME_search13, carrier_frames_stand, NULL};
                    571: 
                    572: mframe_t carrier_frames_walk [] =
                    573: {
                    574: //     ai_walk,        12,     drawbbox,
                    575:        ai_walk,        4,      NULL,
                    576:        ai_walk,        4,      NULL,
                    577:        ai_walk,        4,      NULL,
                    578:        ai_walk,        4,      NULL,
                    579:        ai_walk,        4,      NULL,
                    580:        ai_walk,        4,      NULL,
                    581:        ai_walk,        4,      NULL,
                    582:        ai_walk,        4,      NULL,
                    583:        ai_walk,        4,      NULL,
                    584:        ai_walk,        4,      NULL,
                    585:        ai_walk,        4,      NULL,
                    586:        ai_walk,        4,      NULL,
                    587:        ai_walk,        4,      NULL
                    588: };
                    589: mmove_t carrier_move_walk = {FRAME_search01, FRAME_search13, carrier_frames_walk, NULL};
                    590: 
                    591: 
                    592: mframe_t carrier_frames_run [] =
                    593: {
                    594: //     ai_run, 12,     drawbbox,
                    595:        ai_run, 6,      CarrierCoopCheck,
                    596:        ai_run, 6,      CarrierCoopCheck,
                    597:        ai_run, 6,      CarrierCoopCheck,
                    598:        ai_run, 6,      CarrierCoopCheck,
                    599:        ai_run, 6,      CarrierCoopCheck,
                    600:        ai_run, 6,      CarrierCoopCheck,
                    601:        ai_run, 6,      CarrierCoopCheck,
                    602:        ai_run, 6,      CarrierCoopCheck,
                    603:        ai_run, 6,      CarrierCoopCheck,
                    604:        ai_run, 6,      CarrierCoopCheck,
                    605:        ai_run, 6,      CarrierCoopCheck,
                    606:        ai_run, 6,      CarrierCoopCheck,
                    607:        ai_run, 6,      CarrierCoopCheck
                    608: };
                    609: mmove_t carrier_move_run = {FRAME_search01, FRAME_search13, carrier_frames_run, NULL};
                    610: 
                    611: mframe_t carrier_frames_attack_pre_mg [] =
                    612: {
                    613:        ai_charge,      4,      CarrierCoopCheck,
                    614:        ai_charge,      4,      CarrierCoopCheck,
                    615:        ai_charge,      4,      CarrierCoopCheck,
                    616:        ai_charge,      4,      CarrierCoopCheck,
                    617:        ai_charge,      4,      CarrierCoopCheck,
                    618:        ai_charge,      4,      CarrierCoopCheck,
                    619:        ai_charge,      4,      CarrierCoopCheck,
                    620:        ai_charge,      4,      carrier_attack_mg
                    621: };
                    622: mmove_t carrier_move_attack_pre_mg = {FRAME_firea01, FRAME_firea08, carrier_frames_attack_pre_mg, NULL};
                    623: 
                    624: 
                    625: // Loop this
                    626: mframe_t carrier_frames_attack_mg [] =
                    627: {
                    628:        ai_charge,      -2,     CarrierMachineGun,
                    629:        ai_charge,      -2,     CarrierMachineGun,
                    630:        ai_charge,      -2,     carrier_reattack_mg
                    631: /*
                    632:        ai_charge,      0,      CarrierMachineGunHold,
                    633: //     ai_charge,      0,      CarrierMachineGun,
                    634:        ai_charge,      0,      CarrierMachineGun,
                    635:        ai_charge,      0,      carrier_reattack_mg
                    636: */
                    637: };
                    638: mmove_t carrier_move_attack_mg = {FRAME_firea09, FRAME_firea11, carrier_frames_attack_mg, NULL};
                    639: 
                    640: mframe_t carrier_frames_attack_post_mg [] =
                    641: {
                    642:        ai_charge,      4,      CarrierCoopCheck,
                    643:        ai_charge,      4,      CarrierCoopCheck,
                    644:        ai_charge,      4,      CarrierCoopCheck,
                    645:        ai_charge,      4,      CarrierCoopCheck
                    646: };
                    647: mmove_t carrier_move_attack_post_mg = {FRAME_firea12, FRAME_firea15, carrier_frames_attack_post_mg, carrier_run};
                    648: 
                    649: mframe_t carrier_frames_attack_pre_gren [] =
                    650: {
                    651:        ai_charge, 4, CarrierCoopCheck,
                    652:        ai_charge, 4, CarrierCoopCheck,
                    653:        ai_charge, 4, CarrierCoopCheck,
                    654:        ai_charge, 4, CarrierCoopCheck,
                    655:        ai_charge, 4, CarrierCoopCheck,
                    656:        ai_charge, 4, carrier_attack_gren
                    657: };
                    658: mmove_t carrier_move_attack_pre_gren = {FRAME_fireb01, FRAME_fireb06, carrier_frames_attack_pre_gren, NULL};
                    659: 
                    660: mframe_t carrier_frames_attack_gren [] =
                    661: {
                    662:        ai_charge, -15, CarrierGrenade,
                    663:        ai_charge, 4, CarrierCoopCheck,
                    664:        ai_charge, 4, CarrierCoopCheck,
                    665:        ai_charge, 4, carrier_reattack_gren
                    666: };
                    667: mmove_t carrier_move_attack_gren = {FRAME_fireb07, FRAME_fireb10, carrier_frames_attack_gren, NULL};
                    668: 
                    669: mframe_t carrier_frames_attack_post_gren [] =
                    670: {
                    671:        ai_charge, 4, CarrierCoopCheck,
                    672:        ai_charge, 4, CarrierCoopCheck,
                    673:        ai_charge, 4, CarrierCoopCheck,
                    674:        ai_charge, 4, CarrierCoopCheck,
                    675:        ai_charge, 4, CarrierCoopCheck,
                    676:        ai_charge, 4, CarrierCoopCheck
                    677: };
                    678: mmove_t carrier_move_attack_post_gren = {FRAME_fireb11, FRAME_fireb16, carrier_frames_attack_post_gren, carrier_run};
                    679: 
                    680: mframe_t carrier_frames_attack_rocket [] =
                    681: {
                    682:        ai_charge,      15,     CarrierRocket
                    683: };
                    684: mmove_t carrier_move_attack_rocket = {FRAME_fireb01, FRAME_fireb01, carrier_frames_attack_rocket, carrier_run};
                    685: 
                    686: void CarrierRail (edict_t *self)
                    687: {
                    688:        vec3_t  start;
                    689:        vec3_t  dir;
                    690:        vec3_t  forward, right;
                    691: 
                    692:        CarrierCoopCheck(self);
                    693:        AngleVectors (self->s.angles, forward, right, NULL);
                    694:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_RAILGUN], forward, right, start);
                    695: 
                    696:        // calc direction to where we targeted
                    697:        VectorSubtract (self->pos1, start, dir);
                    698:        VectorNormalize (dir);
                    699: 
                    700:        monster_fire_railgun (self, start, dir, 50, 100, MZ2_CARRIER_RAILGUN);
                    701:        self->monsterinfo.attack_finished = level.time + RAIL_FIRE_TIME;
                    702: }
                    703: 
                    704: void CarrierSaveLoc (edict_t *self)
                    705: {
                    706:        CarrierCoopCheck(self);
                    707:        VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot
                    708:        self->pos1[2] += self->enemy->viewheight;
                    709: };
                    710: 
                    711: mframe_t carrier_frames_attack_rail [] =
                    712: {
                    713:        ai_charge, 2, CarrierCoopCheck,
                    714:        ai_charge, 2, CarrierSaveLoc,
                    715:        ai_charge, 2, CarrierCoopCheck,
                    716:        ai_charge, -20, CarrierRail,
                    717:        ai_charge, 2, CarrierCoopCheck,
                    718:        ai_charge, 2, CarrierCoopCheck,
                    719:        ai_charge, 2, CarrierCoopCheck,
                    720:        ai_charge, 2, CarrierCoopCheck,
                    721:        ai_charge, 2, CarrierCoopCheck
                    722: };
                    723: mmove_t carrier_move_attack_rail = {FRAME_search01, FRAME_search09, carrier_frames_attack_rail, carrier_run};
                    724: 
                    725: mframe_t carrier_frames_spawn [] =
                    726: {
                    727:        ai_charge,      -2,     CarrierMachineGun,
                    728:        ai_charge,      -2,     CarrierMachineGun,
                    729:        ai_charge,      -2,     CarrierMachineGun,
                    730:        ai_charge,      -2,     CarrierMachineGun,
                    731:        ai_charge,      -2,     CarrierMachineGun,
                    732:        ai_charge,      -2,     CarrierMachineGun,
                    733:        ai_charge,      -2,     carrier_prep_spawn,             // 7 - end of wind down
                    734:        ai_charge,      -2,     carrier_start_spawn,            // 8 - start of spawn
                    735:        ai_charge,      -2,     carrier_ready_spawn,
                    736:        ai_charge,      -2,     CarrierMachineGun,
                    737:        ai_charge,      -2,     CarrierMachineGun,
                    738:        ai_charge,      -10, carrier_spawn_check,               //12 - actual spawn
                    739:        ai_charge,      -2,     CarrierMachineGun,              //13 - begin of wind down
                    740:        ai_charge,      -2,     CarrierMachineGun,
                    741:        ai_charge,      -2,     CarrierMachineGun,
                    742:        ai_charge,      -2,     CarrierMachineGun,
                    743:        ai_charge,      -2,     CarrierMachineGun,
                    744:        ai_charge,      -2,     carrier_reattack_mg             //18 - end of wind down
                    745: };
                    746: mmove_t carrier_move_spawn = {FRAME_spawn01, FRAME_spawn18, carrier_frames_spawn, NULL};
                    747: 
                    748: mframe_t carrier_frames_pain_heavy [] =
                    749: {
                    750:        ai_move,        0,      NULL,
                    751:        ai_move,        0,      NULL,
                    752:        ai_move,        0,      NULL,
                    753:        ai_move,        0,      NULL,
                    754:        ai_move,        0,      NULL,
                    755:        ai_move,        0,      NULL,
                    756:        ai_move,        0,      NULL,
                    757:        ai_move,        0,      NULL,
                    758:        ai_move,        0,      NULL,
                    759:        ai_move,        0,      NULL
                    760: };
                    761: mmove_t carrier_move_pain_heavy = {FRAME_death01, FRAME_death10, carrier_frames_pain_heavy, carrier_run};
                    762: 
                    763: mframe_t carrier_frames_pain_light [] =
                    764: {
                    765:        ai_move,        0,      NULL,
                    766:        ai_move,        0,      NULL,
                    767:        ai_move,        0,      NULL,
                    768:        ai_move,        0,      NULL
                    769: };
                    770: mmove_t carrier_move_pain_light = {FRAME_spawn01, FRAME_spawn04, carrier_frames_pain_light, carrier_run};
                    771: 
                    772: mframe_t carrier_frames_death [] =
                    773: {
                    774:        ai_move,        0,      NULL,
                    775:        ai_move,        0,      NULL,
                    776:        ai_move,        0,      NULL,
                    777:        ai_move,        0,      NULL,
                    778:        ai_move,        0,      NULL,
                    779:        ai_move,        0,      NULL,
                    780:        ai_move,        0,      NULL,
                    781:        ai_move,        0,      NULL,
                    782:        ai_move,        0,      NULL,
                    783:        ai_move,        0,      NULL,
                    784:        ai_move,        0,      NULL,
                    785:        ai_move,        0,      NULL,
                    786:        ai_move,        0,      NULL,
                    787:        ai_move,        0,      NULL,
                    788:        ai_move,        0,      NULL,
                    789:        ai_move,        0,      BossExplode
                    790: };
                    791: mmove_t carrier_move_death = {FRAME_death01, FRAME_death16, carrier_frames_death, carrier_dead};
                    792: 
                    793: void carrier_stand (edict_t *self)
                    794: {
                    795: //     gi.dprintf ("carrier stand\n");
                    796:        self->monsterinfo.currentmove = &carrier_move_stand;
                    797: }
                    798: 
                    799: void carrier_run (edict_t *self)
                    800: {
                    801: 
                    802: //     gi.dprintf ("carrier run - %2.2f - %s \n", level.time, self->enemy->classname);
                    803:        self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
                    804: 
                    805:        if (self->monsterinfo.aiflags & AI_STAND_GROUND)
                    806:                self->monsterinfo.currentmove = &carrier_move_stand;
                    807:        else
                    808:                self->monsterinfo.currentmove = &carrier_move_run;
                    809: }
                    810: 
                    811: void carrier_walk (edict_t *self)
                    812: {
                    813:        self->monsterinfo.currentmove = &carrier_move_walk;
                    814: }
                    815: 
                    816: void CarrierMachineGunHold (edict_t *self)
                    817: {
                    818: //     self->monsterinfo.aiflags |= AI_HOLD_FRAME;
                    819: //     self->yaw_speed = 0;
                    820: //     self->monsterinfo.currentmove = &carrier_move_attack_mg;
                    821:        CarrierMachineGun (self);
                    822: }
                    823: 
                    824: void carrier_attack (edict_t *self)
                    825: {
                    826:        vec3_t  vec;
                    827:        float   range, luck;
                    828:        qboolean        enemy_inback, enemy_infront, enemy_below;
                    829: 
                    830: //     gi.dprintf ("carrier attack\n");
                    831:        
                    832:        self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
                    833: 
                    834:        if (!self->enemy)
                    835:                return;
                    836: 
                    837:        enemy_inback = inback(self, self->enemy);
                    838:        enemy_infront = infront (self, self->enemy);
                    839:        enemy_below = below (self, self->enemy);
                    840: 
                    841:        if (self->bad_area)
                    842:        {
                    843:                if ((enemy_inback) || (enemy_below))
                    844:                        self->monsterinfo.currentmove = &carrier_move_attack_rocket;
                    845:                else if ((random() < 0.1) || (level.time < self->monsterinfo.attack_finished))
                    846:                        self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
                    847:                else
                    848:                {
                    849:                        gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
                    850:                        self->monsterinfo.currentmove = &carrier_move_attack_rail;
                    851:                }
                    852:                return;
                    853:        }
                    854: 
                    855:        if (self->monsterinfo.attack_state == AS_BLIND)
                    856:        {
                    857:                self->monsterinfo.currentmove = &carrier_move_spawn;
                    858:                return;
                    859:        }
                    860: 
                    861:        if (!enemy_inback && !enemy_infront && !enemy_below) // to side and not under
                    862:        {
                    863:                if ((random() < 0.1) || (level.time < self->monsterinfo.attack_finished)) 
                    864:                        self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
                    865:                else
                    866:                {
                    867:                        gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
                    868:                        self->monsterinfo.currentmove = &carrier_move_attack_rail;
                    869:                }
                    870:                return;
                    871:        }
                    872: 
                    873: /*     if ((g_showlogic) && (g_showlogic->value))
                    874:        {
                    875:                gi.dprintf ("checking enemy ..");
                    876:                if (enemy_inback)
                    877:                        gi.dprintf (" in back\n");
                    878:                else if (enemy_infront)
                    879:                        gi.dprintf (" in front\n");
                    880:                else
                    881:                        gi.dprintf (" inaccessible\n");
                    882:        }
                    883: */     
                    884:        if (enemy_infront)
                    885:        {
                    886:                VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
                    887:                range = VectorLength (vec);
                    888:                if (range <= 125)
                    889:                {
                    890:                        if ((random() < 0.8) || (level.time < self->monsterinfo.attack_finished))
                    891:                                self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
                    892:                        else
                    893:                        {
                    894:                                gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
                    895:                                self->monsterinfo.currentmove = &carrier_move_attack_rail;
                    896:                        }
                    897:                }
                    898:                else if (range < 600)
                    899:                {
                    900:                        luck = random();
                    901:                        if (self->monsterinfo.monster_slots > 2)
                    902:                        {
                    903:                                if (luck <= 0.20)
                    904:                                        self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
                    905:                                else if (luck <= 0.40)
                    906:                                        self->monsterinfo.currentmove = &carrier_move_attack_pre_gren;
                    907:                                else if ((luck <= 0.7) && !(level.time < self->monsterinfo.attack_finished))
                    908:                                {
                    909:                                        gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
                    910:                                        self->monsterinfo.currentmove = &carrier_move_attack_rail;
                    911:                                }
                    912:                                else
                    913:                                        self->monsterinfo.currentmove = &carrier_move_spawn;
                    914:                        }
                    915:                        else
                    916:                        {
                    917:                                if (luck <= 0.30)
                    918:                                        self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
                    919:                                else if (luck <= 0.65)
                    920:                                        self->monsterinfo.currentmove = &carrier_move_attack_pre_gren;
                    921:                                else if (level.time >= self->monsterinfo.attack_finished)
                    922:                                {
                    923:                                        gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
                    924:                                        self->monsterinfo.currentmove = &carrier_move_attack_rail;
                    925:                                }
                    926:                                else
                    927:                                        self->monsterinfo.currentmove = &carrier_move_spawn;
                    928:                        }
                    929:                }
                    930:                else // won't use grenades at this range
                    931:                {
                    932:                        luck = random();
                    933:                        if (self->monsterinfo.monster_slots > 2)
                    934:                        {
                    935:                                if (luck < 0.3)
                    936:                                        self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
                    937:                                else if ((luck < 0.65) && !(level.time < self->monsterinfo.attack_finished))
                    938:                                {
                    939:                                        gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
                    940:                                        VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot
                    941:                                        self->pos1[2] += self->enemy->viewheight;
                    942:                                        self->monsterinfo.currentmove = &carrier_move_attack_rail;
                    943:                                }
                    944:                                else
                    945:                                        self->monsterinfo.currentmove = &carrier_move_spawn;
                    946:                        }
                    947:                        else
                    948:                        {
                    949:                                if ((luck < 0.45) || (level.time < self->monsterinfo.attack_finished))
                    950:                                        self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
                    951:                                else
                    952:                                {
                    953:                                        gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
                    954:                                        self->monsterinfo.currentmove = &carrier_move_attack_rail;
                    955:                                }
                    956:                        }
                    957:                }
                    958:        }
                    959:        else if ((enemy_below) || (enemy_inback))
                    960:        {
                    961:                self->monsterinfo.currentmove = &carrier_move_attack_rocket;
                    962:        }
                    963: }
                    964: 
                    965: void carrier_attack_mg (edict_t *self)
                    966: {
                    967:        CarrierCoopCheck(self);
                    968:        self->monsterinfo.currentmove = &carrier_move_attack_mg;
                    969: }
                    970: 
                    971: void carrier_reattack_mg (edict_t *self)
                    972: {
                    973:        CarrierCoopCheck(self);
                    974:        if ( infront(self, self->enemy) )
                    975:                if (random() <= 0.5)
                    976:                        if ((random() < 0.7) || (self->monsterinfo.monster_slots <= 2))
                    977:                                self->monsterinfo.currentmove = &carrier_move_attack_mg;
                    978:                        else
                    979:                                self->monsterinfo.currentmove = &carrier_move_spawn;
                    980:                else
                    981:                        self->monsterinfo.currentmove = &carrier_move_attack_post_mg;
                    982:        else
                    983:                self->monsterinfo.currentmove = &carrier_move_attack_post_mg;
                    984: }
                    985: 
                    986: 
                    987: void carrier_attack_gren (edict_t *self)
                    988: {
                    989: //     gi.dprintf ("carrier_attack_gren - %2.2f\n",level.time);
                    990:        CarrierCoopCheck(self);
                    991:        self->timestamp = level.time;
                    992:        self->monsterinfo.currentmove = &carrier_move_attack_gren;
                    993: }
                    994: 
                    995: void carrier_reattack_gren (edict_t *self)
                    996: {
                    997:        CarrierCoopCheck(self);
                    998: //     gi.dprintf ("carrier_reattack - %2.2f", level.time);
                    999:        if ( infront(self, self->enemy) )
                   1000:                if (self->timestamp + 1.3 > level.time ) // four grenades
                   1001:                {
                   1002: //                     gi.dprintf (" attacking\n");
                   1003:                        self->monsterinfo.currentmove = &carrier_move_attack_gren;
                   1004:                        return;
                   1005:                }
                   1006: //     gi.dprintf ("not attacking\n");
                   1007:        self->monsterinfo.currentmove = &carrier_move_attack_post_gren;
                   1008: }
                   1009: 
                   1010: 
                   1011: void carrier_pain (edict_t *self, edict_t *other, float kick, int damage)
                   1012: {
                   1013:        qboolean changed = false;
                   1014: 
                   1015:        if (self->health < (self->max_health / 2))
                   1016:                self->s.skinnum = 1;
                   1017: 
                   1018:        if (skill->value == 3)
                   1019:                return;         // no pain anims in nightmare
                   1020: 
                   1021:        //      gi.dprintf ("carrier pain\n");
                   1022:        if (level.time < self->pain_debounce_time)
                   1023:                return;
                   1024: 
                   1025:        self->pain_debounce_time = level.time + 3;
                   1026: 
                   1027:        // right now, the carrier doesn't go into his pain animations
                   1028:        if (damage < 10)
                   1029:        {
                   1030:                gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0);
                   1031:        }
                   1032:        else if (damage < 30)
                   1033:        {
                   1034:                gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0);
                   1035:                if (random() < 0.5)
                   1036:                {
                   1037:                        changed = true;
                   1038:                        self->monsterinfo.currentmove = &carrier_move_pain_light;
                   1039:                }
                   1040:        }
                   1041:        else 
                   1042:        {
                   1043:                gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0);
                   1044:                self->monsterinfo.currentmove = &carrier_move_pain_heavy;
                   1045:                changed = true;
                   1046:        }
                   1047: 
                   1048:        // if we changed frames, clean up our little messes
                   1049:        if (changed)
                   1050:        {
                   1051:                self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
                   1052:                self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
                   1053:                self->yaw_speed = orig_yaw_speed;
                   1054:        }
                   1055: }
                   1056: 
                   1057: void carrier_dead (edict_t *self)
                   1058: {
                   1059:        VectorSet (self->mins, -56, -56, 0);
                   1060:        VectorSet (self->maxs, 56, 56, 80);
                   1061:        self->movetype = MOVETYPE_TOSS;
                   1062:        self->svflags |= SVF_DEADMONSTER;
                   1063:        self->nextthink = 0;
                   1064:        gi.linkentity (self);
                   1065: }
                   1066: 
                   1067: void carrier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                   1068: {
                   1069:        gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
                   1070:        self->deadflag = DEAD_DEAD;
                   1071:        self->takedamage = DAMAGE_NO;
                   1072:        self->count = 0;
                   1073:        self->monsterinfo.currentmove = &carrier_move_death;
                   1074: }
                   1075: 
                   1076: qboolean Carrier_CheckAttack (edict_t *self)
                   1077: {
                   1078:        vec3_t  spot1, spot2;
                   1079:        vec3_t  temp;
                   1080:        float   chance;
                   1081:        trace_t tr;
                   1082:        qboolean        enemy_infront, enemy_inback, enemy_below;
                   1083:        int                     enemy_range;
                   1084:        float           enemy_yaw;
                   1085: 
                   1086:        if (self->enemy->health > 0)
                   1087:        {
                   1088:        // see if any entities are in the way of the shot
                   1089:                VectorCopy (self->s.origin, spot1);
                   1090:                spot1[2] += self->viewheight;
                   1091:                VectorCopy (self->enemy->s.origin, spot2);
                   1092:                spot2[2] += self->enemy->viewheight;
                   1093: 
                   1094:                tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
                   1095: 
                   1096:                // do we have a clear shot?
                   1097:                if (tr.ent != self->enemy)
                   1098:                {       
                   1099:                        // go ahead and spawn stuff if we're mad a a client
                   1100:                        if (self->enemy->client && self->monsterinfo.monster_slots >= 2)
                   1101:                        {
                   1102:                                self->monsterinfo.attack_state = AS_BLIND;
                   1103:                                return true;
                   1104:                        }
                   1105:                                
                   1106:                        // PGM - we want them to go ahead and shoot at info_notnulls if they can.
                   1107:                        if(self->enemy->solid != SOLID_NOT || tr.fraction < 1.0)                //PGM
                   1108:                                return false;
                   1109:                }
                   1110:        }
                   1111:        
                   1112:        enemy_infront = infront(self, self->enemy);
                   1113:        enemy_inback = inback(self, self->enemy);
                   1114:        enemy_below = below (self, self->enemy);
                   1115: 
                   1116:        enemy_range = range(self, self->enemy);
                   1117:        VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
                   1118:        enemy_yaw = vectoyaw2(temp);
                   1119: 
                   1120:        self->ideal_yaw = enemy_yaw;
                   1121: 
                   1122:        // PMM - shoot out the back if appropriate
                   1123:        if ((enemy_inback) || (!enemy_infront && enemy_below))
                   1124:        {
                   1125:                // this is using wait because the attack is supposed to be independent
                   1126:                if (level.time >= self->wait)
                   1127:                {
                   1128:                        self->wait = level.time + CARRIER_ROCKET_TIME;
                   1129:                        self->monsterinfo.attack(self);
                   1130:                        if (random() < 0.6)
                   1131:                                self->monsterinfo.attack_state = AS_SLIDING;
                   1132:                        else
                   1133:                                self->monsterinfo.attack_state = AS_STRAIGHT;
                   1134:                        return true;
                   1135:                }
                   1136:        }
                   1137: 
                   1138:        // melee attack
                   1139:        if (enemy_range == RANGE_MELEE)
                   1140:        {
                   1141:                self->monsterinfo.attack_state = AS_MISSILE;
                   1142:                return true;
                   1143:        }
                   1144:        
                   1145: //     if (level.time < self->monsterinfo.attack_finished)
                   1146: //             return false;
                   1147: 
                   1148:        if (self->monsterinfo.aiflags & AI_STAND_GROUND)
                   1149:        {
                   1150:                chance = 0.4;
                   1151:        }
                   1152:        else if (enemy_range == RANGE_MELEE)
                   1153:        {
                   1154:                chance = 0.8;
                   1155:        }
                   1156:        else if (enemy_range == RANGE_NEAR)
                   1157:        {
                   1158:                chance = 0.8;
                   1159:        }
                   1160:        else if (enemy_range == RANGE_MID)
                   1161:        {
                   1162:                chance = 0.8;
                   1163:        }
                   1164:        else if (enemy_range == RANGE_FAR)
                   1165:        {
                   1166:                chance = 0.5;
                   1167:        }
                   1168: 
                   1169:        // PGM - go ahead and shoot every time if it's a info_notnull
                   1170:        if ((random () < chance) || (self->enemy->solid == SOLID_NOT))
                   1171:        {
                   1172:                self->monsterinfo.attack_state = AS_MISSILE;
                   1173: //             self->monsterinfo.attack_finished = level.time + 2*random();
                   1174:                return true;
                   1175:        }
                   1176: 
                   1177:        if (self->flags & FL_FLY)
                   1178:        {
                   1179:                if (random() < 0.6)
                   1180:                        self->monsterinfo.attack_state = AS_SLIDING;
                   1181:                else
                   1182:                        self->monsterinfo.attack_state = AS_STRAIGHT;
                   1183:        }
                   1184: 
                   1185:        return false;
                   1186: }
                   1187: 
                   1188: void CarrierPrecache ()
                   1189: {
                   1190:        gi.soundindex ("flyer/flysght1.wav");
                   1191:        gi.soundindex ("flyer/flysrch1.wav");
                   1192:        gi.soundindex ("flyer/flypain1.wav");
                   1193:        gi.soundindex ("flyer/flypain2.wav");
                   1194:        gi.soundindex ("flyer/flyatck2.wav");
                   1195:        gi.soundindex ("flyer/flyatck1.wav");
                   1196:        gi.soundindex ("flyer/flydeth1.wav");
                   1197:        gi.soundindex ("flyer/flyatck3.wav");
                   1198:        gi.soundindex ("flyer/flyidle1.wav");
                   1199:        gi.soundindex ("weapons/rockfly.wav");
                   1200:        gi.soundindex ("infantry/infatck1.wav");
                   1201:        gi.soundindex ("gunner/gunatck3.wav");
                   1202:        gi.soundindex ("weapons/grenlb1b.wav");
                   1203:        gi.soundindex ("tank/rocket.wav");
                   1204: 
                   1205:        gi.modelindex ("models/monsters/flyer/tris.md2");
                   1206:        gi.modelindex ("models/objects/rocket/tris.md2");
                   1207:        gi.modelindex ("models/objects/debris2/tris.md2");
                   1208:        gi.modelindex ("models/objects/grenade/tris.md2");
                   1209:        gi.modelindex("models/items/spawngro/tris.md2");
                   1210:        gi.modelindex("models/items/spawngro2/tris.md2");
                   1211:        gi.modelindex ("models/objects/gibs/sm_metal/tris.md2");
                   1212:        gi.modelindex ("models/objects/gibs/gear/tris.md2");
                   1213: }
                   1214: 
                   1215: 
                   1216: /*QUAKED monster_carrier (1 .5 0) (-56 -56 -44) (56 56 44) Ambush Trigger_Spawn Sight
                   1217: */
                   1218: void SP_monster_carrier (edict_t *self)
                   1219: {
                   1220:        if (deathmatch->value)
                   1221:        {
                   1222:                G_FreeEdict (self);
                   1223:                return;
                   1224:        }
                   1225: 
                   1226:        sound_pain1 = gi.soundindex ("bosshovr/bhvpain1.wav");
                   1227:        sound_pain2 = gi.soundindex ("bosshovr/bhvpain2.wav");
                   1228:        sound_pain3 = gi.soundindex ("bosshovr/bhvpain3.wav");
                   1229:        sound_death = gi.soundindex ("bosshovr/bhvdeth1.wav");
                   1230:        sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav");
                   1231:        sound_rail = gi.soundindex ("gladiator/railgun.wav");
                   1232: 
                   1233:        self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav");
                   1234: 
                   1235:        self->movetype = MOVETYPE_STEP;
                   1236:        self->solid = SOLID_BBOX;
                   1237:        self->s.modelindex = gi.modelindex ("models/monsters/carrier/tris.md2");
                   1238:        VectorSet (self->mins, -56, -56, -44);
                   1239:        VectorSet (self->maxs, 56, 56, 44);
                   1240: 
                   1241:        // 2000 - 4000 health
                   1242:        self->health = max (2000, 2000 + 1000*((skill->value)-1));
                   1243:        self->gib_health = -200;
                   1244:        self->mass = 1000;
                   1245: 
                   1246:        self->yaw_speed = 15;
                   1247:        orig_yaw_speed = self->yaw_speed;
                   1248: //     self->yaw_speed = 1;
                   1249:        
                   1250:        self->flags |= FL_IMMUNE_LASER;
                   1251:        self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
                   1252: 
                   1253:        self->pain = carrier_pain;
                   1254:        self->die = carrier_die;
                   1255: 
                   1256:        self->monsterinfo.melee = NULL;
                   1257:        self->monsterinfo.stand = carrier_stand;
                   1258:        self->monsterinfo.walk = carrier_walk;
                   1259:        self->monsterinfo.run = carrier_run;
                   1260:        self->monsterinfo.attack = carrier_attack;
                   1261:        self->monsterinfo.search = carrier_search;
                   1262:        self->monsterinfo.checkattack = Carrier_CheckAttack;
                   1263:        gi.linkentity (self);
                   1264: 
                   1265:        self->monsterinfo.currentmove = &carrier_move_stand;    
                   1266:        self->monsterinfo.scale = MODEL_SCALE;
                   1267: 
                   1268:        CarrierPrecache();
                   1269: 
                   1270:        flymonster_start (self);
                   1271: 
                   1272:        self->monsterinfo.attack_finished = 0;
                   1273:        switch ((int)skill->value)
                   1274:        {
                   1275:        case 0:
                   1276:                self->monsterinfo.monster_slots = 3;
                   1277:                break;
                   1278:        case 1:
                   1279:        case 2:
                   1280:                self->monsterinfo.monster_slots = 6;
                   1281:                break;
                   1282:        case 3:
                   1283:                self->monsterinfo.monster_slots = 9;
                   1284:                break;
                   1285:        default:
                   1286:                self->monsterinfo.monster_slots = 6;
                   1287:                break;
                   1288:        }
                   1289: }
                   1290: 

unix.superglobalmegacorp.com

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