Annotation of quake2/rogue/m_carrier.c, revision 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.