Annotation of quake2/rogue/m_tank.c, revision 1.1

1.1     ! root        1: /*
        !             2: ==============================================================================
        !             3: 
        !             4: TANK
        !             5: 
        !             6: ==============================================================================
        !             7: */
        !             8: 
        !             9: #include "g_local.h"
        !            10: #include "m_tank.h"
        !            11: 
        !            12: 
        !            13: void tank_refire_rocket (edict_t *self);
        !            14: void tank_doattack_rocket (edict_t *self);
        !            15: void tank_reattack_blaster (edict_t *self);
        !            16: 
        !            17: static int     sound_thud;
        !            18: static int     sound_pain;
        !            19: static int     sound_idle;
        !            20: static int     sound_die;
        !            21: static int     sound_step;
        !            22: static int     sound_sight;
        !            23: static int     sound_windup;
        !            24: static int     sound_strike;
        !            25: 
        !            26: //
        !            27: // misc
        !            28: //
        !            29: 
        !            30: void tank_sight (edict_t *self, edict_t *other)
        !            31: {
        !            32:        gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
        !            33: }
        !            34: 
        !            35: 
        !            36: void tank_footstep (edict_t *self)
        !            37: {
        !            38:        gi.sound (self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
        !            39: }
        !            40: 
        !            41: void tank_thud (edict_t *self)
        !            42: {
        !            43:        gi.sound (self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0);
        !            44: }
        !            45: 
        !            46: void tank_windup (edict_t *self)
        !            47: {
        !            48:        gi.sound (self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
        !            49: }
        !            50: 
        !            51: void tank_idle (edict_t *self)
        !            52: {
        !            53:        gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
        !            54: }
        !            55: 
        !            56: 
        !            57: //
        !            58: // stand
        !            59: //
        !            60: 
        !            61: mframe_t tank_frames_stand []=
        !            62: {
        !            63:        ai_stand, 0, NULL,
        !            64:        ai_stand, 0, NULL,
        !            65:        ai_stand, 0, NULL,
        !            66:        ai_stand, 0, NULL,
        !            67:        ai_stand, 0, NULL,
        !            68:        ai_stand, 0, NULL,
        !            69:        ai_stand, 0, NULL,
        !            70:        ai_stand, 0, NULL,
        !            71:        ai_stand, 0, NULL,
        !            72:        ai_stand, 0, NULL,
        !            73:        ai_stand, 0, NULL,
        !            74:        ai_stand, 0, NULL,
        !            75:        ai_stand, 0, NULL,
        !            76:        ai_stand, 0, NULL,
        !            77:        ai_stand, 0, NULL,
        !            78:        ai_stand, 0, NULL,
        !            79:        ai_stand, 0, NULL,
        !            80:        ai_stand, 0, NULL,
        !            81:        ai_stand, 0, NULL,
        !            82:        ai_stand, 0, NULL,
        !            83:        ai_stand, 0, NULL,
        !            84:        ai_stand, 0, NULL,
        !            85:        ai_stand, 0, NULL,
        !            86:        ai_stand, 0, NULL,
        !            87:        ai_stand, 0, NULL,
        !            88:        ai_stand, 0, NULL,
        !            89:        ai_stand, 0, NULL,
        !            90:        ai_stand, 0, NULL,
        !            91:        ai_stand, 0, NULL,
        !            92:        ai_stand, 0, NULL
        !            93: };
        !            94: mmove_t        tank_move_stand = {FRAME_stand01, FRAME_stand30, tank_frames_stand, NULL};
        !            95:        
        !            96: void tank_stand (edict_t *self)
        !            97: {
        !            98:        self->monsterinfo.currentmove = &tank_move_stand;
        !            99: }
        !           100: 
        !           101: 
        !           102: //
        !           103: // walk
        !           104: //
        !           105: 
        !           106: void tank_walk (edict_t *self);
        !           107: 
        !           108: mframe_t tank_frames_start_walk [] =
        !           109: {
        !           110:        ai_walk,  0, NULL,
        !           111:        ai_walk,  6, NULL,
        !           112:        ai_walk,  6, NULL,
        !           113:        ai_walk, 11, tank_footstep
        !           114: };
        !           115: mmove_t        tank_move_start_walk = {FRAME_walk01, FRAME_walk04, tank_frames_start_walk, tank_walk};
        !           116: 
        !           117: mframe_t tank_frames_walk [] =
        !           118: {
        !           119:        ai_walk, 4,     NULL,
        !           120:        ai_walk, 5,     NULL,
        !           121:        ai_walk, 3,     NULL,
        !           122:        ai_walk, 2,     NULL,
        !           123:        ai_walk, 5,     NULL,
        !           124:        ai_walk, 5,     NULL,
        !           125:        ai_walk, 4,     NULL,
        !           126:        ai_walk, 4,     tank_footstep,
        !           127:        ai_walk, 3,     NULL,
        !           128:        ai_walk, 5,     NULL,
        !           129:        ai_walk, 4,     NULL,
        !           130:        ai_walk, 5,     NULL,
        !           131:        ai_walk, 7,     NULL,
        !           132:        ai_walk, 7,     NULL,
        !           133:        ai_walk, 6,     NULL,
        !           134:        ai_walk, 6,     tank_footstep
        !           135: };
        !           136: mmove_t        tank_move_walk = {FRAME_walk05, FRAME_walk20, tank_frames_walk, NULL};
        !           137: 
        !           138: mframe_t tank_frames_stop_walk [] =
        !           139: {
        !           140:        ai_walk,  3, NULL,
        !           141:        ai_walk,  3, NULL,
        !           142:        ai_walk,  2, NULL,
        !           143:        ai_walk,  2, NULL,
        !           144:        ai_walk,  4, tank_footstep
        !           145: };
        !           146: mmove_t        tank_move_stop_walk = {FRAME_walk21, FRAME_walk25, tank_frames_stop_walk, tank_stand};
        !           147: 
        !           148: void tank_walk (edict_t *self)
        !           149: {
        !           150:                self->monsterinfo.currentmove = &tank_move_walk;
        !           151: }
        !           152: 
        !           153: 
        !           154: //
        !           155: // run
        !           156: //
        !           157: 
        !           158: void tank_run (edict_t *self);
        !           159: 
        !           160: mframe_t tank_frames_start_run [] =
        !           161: {
        !           162:        ai_run,  0, NULL,
        !           163:        ai_run,  6, NULL,
        !           164:        ai_run,  6, NULL,
        !           165:        ai_run, 11, tank_footstep
        !           166: };
        !           167: mmove_t        tank_move_start_run = {FRAME_walk01, FRAME_walk04, tank_frames_start_run, tank_run};
        !           168: 
        !           169: mframe_t tank_frames_run [] =
        !           170: {
        !           171:        ai_run, 4,      NULL,
        !           172:        ai_run, 5,      NULL,
        !           173:        ai_run, 3,      NULL,
        !           174:        ai_run, 2,      NULL,
        !           175:        ai_run, 5,      NULL,
        !           176:        ai_run, 5,      NULL,
        !           177:        ai_run, 4,      NULL,
        !           178:        ai_run, 4,      tank_footstep,
        !           179:        ai_run, 3,      NULL,
        !           180:        ai_run, 5,      NULL,
        !           181:        ai_run, 4,      NULL,
        !           182:        ai_run, 5,      NULL,
        !           183:        ai_run, 7,      NULL,
        !           184:        ai_run, 7,      NULL,
        !           185:        ai_run, 6,      NULL,
        !           186:        ai_run, 6,      tank_footstep
        !           187: };
        !           188: mmove_t        tank_move_run = {FRAME_walk05, FRAME_walk20, tank_frames_run, NULL};
        !           189: 
        !           190: mframe_t tank_frames_stop_run [] =
        !           191: {
        !           192:        ai_run,  3, NULL,
        !           193:        ai_run,  3, NULL,
        !           194:        ai_run,  2, NULL,
        !           195:        ai_run,  2, NULL,
        !           196:        ai_run,  4, tank_footstep
        !           197: };
        !           198: mmove_t        tank_move_stop_run = {FRAME_walk21, FRAME_walk25, tank_frames_stop_run, tank_walk};
        !           199: 
        !           200: void tank_run (edict_t *self)
        !           201: {
        !           202:        if (self->enemy && self->enemy->client)
        !           203:                self->monsterinfo.aiflags |= AI_BRUTAL;
        !           204:        else
        !           205:                self->monsterinfo.aiflags &= ~AI_BRUTAL;
        !           206: 
        !           207:        if (self->monsterinfo.aiflags & AI_STAND_GROUND)
        !           208:        {
        !           209:                self->monsterinfo.currentmove = &tank_move_stand;
        !           210:                return;
        !           211:        }
        !           212: 
        !           213:        if (self->monsterinfo.currentmove == &tank_move_walk ||
        !           214:                self->monsterinfo.currentmove == &tank_move_start_run)
        !           215:        {
        !           216:                self->monsterinfo.currentmove = &tank_move_run;
        !           217:        }
        !           218:        else
        !           219:        {
        !           220:                self->monsterinfo.currentmove = &tank_move_start_run;
        !           221:        }
        !           222: }
        !           223: 
        !           224: //
        !           225: // pain
        !           226: //
        !           227: 
        !           228: mframe_t tank_frames_pain1 [] =
        !           229: {
        !           230:        ai_move, 0, NULL,
        !           231:        ai_move, 0, NULL,
        !           232:        ai_move, 0, NULL,
        !           233:        ai_move, 0, NULL
        !           234: };
        !           235: mmove_t tank_move_pain1 = {FRAME_pain101, FRAME_pain104, tank_frames_pain1, tank_run};
        !           236: 
        !           237: mframe_t tank_frames_pain2 [] =
        !           238: {
        !           239:        ai_move, 0, NULL,
        !           240:        ai_move, 0, NULL,
        !           241:        ai_move, 0, NULL,
        !           242:        ai_move, 0, NULL,
        !           243:        ai_move, 0, NULL
        !           244: };
        !           245: mmove_t tank_move_pain2 = {FRAME_pain201, FRAME_pain205, tank_frames_pain2, tank_run};
        !           246: 
        !           247: mframe_t tank_frames_pain3 [] =
        !           248: {
        !           249:        ai_move, -7, NULL,
        !           250:        ai_move, 0,  NULL,
        !           251:        ai_move, 0,  NULL,
        !           252:        ai_move, 0,  NULL,
        !           253:        ai_move, 2,  NULL,
        !           254:        ai_move, 0,  NULL,
        !           255:        ai_move, 0,  NULL,
        !           256:        ai_move, 3,  NULL,
        !           257:        ai_move, 0,  NULL,
        !           258:        ai_move, 2,  NULL,
        !           259:        ai_move, 0,  NULL,
        !           260:        ai_move, 0,  NULL,
        !           261:        ai_move, 0,  NULL,
        !           262:        ai_move, 0,  NULL,
        !           263:        ai_move, 0,  NULL,
        !           264:        ai_move, 0,  tank_footstep
        !           265: };
        !           266: mmove_t        tank_move_pain3 = {FRAME_pain301, FRAME_pain316, tank_frames_pain3, tank_run};
        !           267: 
        !           268: 
        !           269: void tank_pain (edict_t *self, edict_t *other, float kick, int damage)
        !           270: {
        !           271:        if (self->health < (self->max_health / 2))
        !           272:                        self->s.skinnum |= 1;
        !           273: 
        !           274:        if (damage <= 10)
        !           275:                return;
        !           276: 
        !           277:        if (level.time < self->pain_debounce_time)
        !           278:                        return;
        !           279: 
        !           280:        if (damage <= 30)
        !           281:                if (random() > 0.2)
        !           282:                        return;
        !           283:        
        !           284:        // If hard or nightmare, don't go into pain while attacking
        !           285:        if ( skill->value >= 2)
        !           286:        {
        !           287:                if ( (self->s.frame >= FRAME_attak301) && (self->s.frame <= FRAME_attak330) )
        !           288:                        return;
        !           289:                if ( (self->s.frame >= FRAME_attak101) && (self->s.frame <= FRAME_attak116) )
        !           290:                        return;
        !           291:        }
        !           292: 
        !           293:        self->pain_debounce_time = level.time + 3;
        !           294:        gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
        !           295: 
        !           296:        if (skill->value == 3)
        !           297:                return;         // no pain anims in nightmare
        !           298: 
        !           299:        // PMM - blindfire cleanup
        !           300:        self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
        !           301:        // pmm
        !           302: 
        !           303:        if (damage <= 30)
        !           304:                self->monsterinfo.currentmove = &tank_move_pain1;
        !           305:        else if (damage <= 60)
        !           306:                self->monsterinfo.currentmove = &tank_move_pain2;
        !           307:        else
        !           308:                self->monsterinfo.currentmove = &tank_move_pain3;
        !           309: };
        !           310: 
        !           311: 
        !           312: //
        !           313: // attacks
        !           314: //
        !           315: 
        !           316: void TankBlaster (edict_t *self)
        !           317: {
        !           318:        vec3_t  forward, right;
        !           319:        vec3_t  start;
        !           320:        vec3_t  end;
        !           321:        vec3_t  dir;
        !           322:        int             flash_number;
        !           323: 
        !           324:        if(!self->enemy || !self->enemy->inuse)         //PGM
        !           325:                return;                                                                 //PGM
        !           326: 
        !           327:        if (self->s.frame == FRAME_attak110)
        !           328:                flash_number = MZ2_TANK_BLASTER_1;
        !           329:        else if (self->s.frame == FRAME_attak113)
        !           330:                flash_number = MZ2_TANK_BLASTER_2;
        !           331:        else // (self->s.frame == FRAME_attak116)
        !           332:                flash_number = MZ2_TANK_BLASTER_3;
        !           333: 
        !           334:        AngleVectors (self->s.angles, forward, right, NULL);
        !           335:        G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
        !           336: 
        !           337:        VectorCopy (self->enemy->s.origin, end);
        !           338:        end[2] += self->enemy->viewheight;
        !           339:        VectorSubtract (end, start, dir);
        !           340: 
        !           341:        monster_fire_blaster (self, start, dir, 30, 800, flash_number, EF_BLASTER);
        !           342: }      
        !           343: 
        !           344: void TankStrike (edict_t *self)
        !           345: {
        !           346:        gi.sound (self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0);
        !           347: }      
        !           348: 
        !           349: void TankRocket (edict_t *self)
        !           350: {
        !           351:        vec3_t  forward, right;
        !           352:        vec3_t  start;
        !           353:        vec3_t  dir;
        !           354:        vec3_t  vec;
        !           355:        int             flash_number;
        !           356:        trace_t trace;                          // PGM
        !           357:        int             rocketSpeed;            // PGM
        !           358:        // pmm - blindfire support
        !           359:        vec3_t  target;
        !           360:        qboolean blindfire = false;
        !           361: 
        !           362:        if(!self->enemy || !self->enemy->inuse)         //PGM
        !           363:                return;                                                                 //PGM
        !           364: 
        !           365:        // pmm - blindfire check
        !           366:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
        !           367:                blindfire = true;
        !           368:        else
        !           369:                blindfire = false;
        !           370: 
        !           371:        if (self->s.frame == FRAME_attak324)
        !           372:                flash_number = MZ2_TANK_ROCKET_1;
        !           373:        else if (self->s.frame == FRAME_attak327)
        !           374:                flash_number = MZ2_TANK_ROCKET_2;
        !           375:        else // (self->s.frame == FRAME_attak330)
        !           376:                flash_number = MZ2_TANK_ROCKET_3;
        !           377: 
        !           378:        AngleVectors (self->s.angles, forward, right, NULL);
        !           379:        G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
        !           380: 
        !           381:        rocketSpeed = 500 + (100 * skill->value);       // PGM rock & roll.... :)
        !           382: 
        !           383:                // PMM
        !           384:        if (blindfire)
        !           385:                VectorCopy (self->monsterinfo.blind_fire_target, target);
        !           386:        else
        !           387:                VectorCopy (self->enemy->s.origin, target);
        !           388:        // pmm
        !           389: 
        !           390: //     VectorCopy (self->enemy->s.origin, vec);
        !           391: //     vec[2] += self->enemy->viewheight;
        !           392: //     VectorSubtract (vec, start, dir);
        !           393: 
        !           394: //PGM
        !           395:        // PMM - blindfire shooting
        !           396:        if (blindfire)
        !           397:        {
        !           398:                VectorCopy (target, vec);
        !           399:                VectorSubtract (vec, start, dir);
        !           400:        }
        !           401:        // pmm
        !           402:        // don't shoot at feet if they're above me.
        !           403:        else if(random() < 0.66 || (start[2] < self->enemy->absmin[2]))
        !           404:        {
        !           405: //             gi.dprintf("normal shot\n");
        !           406:                VectorCopy (self->enemy->s.origin, vec);
        !           407:                vec[2] += self->enemy->viewheight;
        !           408:                VectorSubtract (vec, start, dir);
        !           409:        }
        !           410:        else
        !           411:        {
        !           412: //             gi.dprintf("shooting at feet!\n");
        !           413:                VectorCopy (self->enemy->s.origin, vec);
        !           414:                vec[2] = self->enemy->absmin[2];
        !           415:                VectorSubtract (vec, start, dir);
        !           416:        }
        !           417: //PGM
        !           418:        
        !           419: //======
        !           420: //PMM - lead target  (not when blindfiring)
        !           421:        // 20, 35, 50, 65 chance of leading
        !           422:        if((!blindfire) && ((random() < (0.2 + ((3 - skill->value) * 0.15)))))
        !           423:        {
        !           424:                float   dist;
        !           425:                float   time;
        !           426: 
        !           427: //             gi.dprintf ("leading target\n");
        !           428:                dist = VectorLength (dir);
        !           429:                time = dist/rocketSpeed;
        !           430:                VectorMA(vec, time, self->enemy->velocity, vec);
        !           431:                VectorSubtract(vec, start, dir);
        !           432:        }
        !           433: //PMM - lead target
        !           434: //======
        !           435: 
        !           436:        VectorNormalize (dir);
        !           437: 
        !           438: //                     gi.WriteByte (svc_temp_entity);
        !           439: //                     gi.WriteByte (TE_DEBUGTRAIL);
        !           440: //                     gi.WritePosition (start);
        !           441: //                     gi.WritePosition (vec);
        !           442: //                     gi.multicast (start, MULTICAST_ALL);
        !           443: 
        !           444:        // pmm blindfire doesn't check target (done in checkattack)
        !           445:        // paranoia, make sure we're not shooting a target right next to us
        !           446:        trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
        !           447:        if (blindfire)
        !           448:        {
        !           449:                // blindfire has different fail criteria for the trace
        !           450:                if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
        !           451:                        monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
        !           452:                else 
        !           453:                {
        !           454:                        // try shifting the target to the left a little (to help counter large offset)
        !           455:                        VectorCopy (target, vec);
        !           456:                        VectorMA (vec, -20, right, vec);
        !           457:                        VectorSubtract(vec, start, dir);
        !           458:                        VectorNormalize (dir);
        !           459:                        trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
        !           460:                        if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
        !           461:                                monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
        !           462:                        else 
        !           463:                        {
        !           464:                                // ok, that failed.  try to the right
        !           465:                                VectorCopy (target, vec);
        !           466:                                VectorMA (vec, 20, right, vec);
        !           467:                                VectorSubtract(vec, start, dir);
        !           468:                                VectorNormalize (dir);
        !           469:                                trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
        !           470:                                if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
        !           471:                                        monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
        !           472:                                else if ((g_showlogic) && (g_showlogic->value))
        !           473:                                        // ok, I give up
        !           474:                                        gi.dprintf ("tank avoiding blindfire shot\n");
        !           475:                        }
        !           476:                }
        !           477:        }
        !           478:        else
        !           479:        {
        !           480:                trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
        !           481:                if(trace.ent == self->enemy || trace.ent == world)
        !           482:                {
        !           483:                        if(trace.fraction > 0.5 || (trace.ent && trace.ent->client))
        !           484:                                monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
        !           485:        //              else
        !           486:        //                      gi.dprintf("didn't make it halfway to target...aborting\n");
        !           487:                }
        !           488:        }
        !           489: }      
        !           490: 
        !           491: void TankMachineGun (edict_t *self)
        !           492: {
        !           493:        vec3_t  dir;
        !           494:        vec3_t  vec;
        !           495:        vec3_t  start;
        !           496:        vec3_t  forward, right;
        !           497:        int             flash_number;
        !           498: 
        !           499:        if(!self->enemy || !self->enemy->inuse)         //PGM
        !           500:                return;                                                                 //PGM
        !           501: 
        !           502:        flash_number = MZ2_TANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak406);
        !           503: 
        !           504:        AngleVectors (self->s.angles, forward, right, NULL);
        !           505:        G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
        !           506: 
        !           507:        if (self->enemy)
        !           508:        {
        !           509:                VectorCopy (self->enemy->s.origin, vec);
        !           510:                vec[2] += self->enemy->viewheight;
        !           511:                VectorSubtract (vec, start, vec);
        !           512:                vectoangles (vec, vec);
        !           513:                dir[0] = vec[0];
        !           514:        }
        !           515:        else
        !           516:        {
        !           517:                dir[0] = 0;
        !           518:        }
        !           519:        if (self->s.frame <= FRAME_attak415)
        !           520:                dir[1] = self->s.angles[1] - 8 * (self->s.frame - FRAME_attak411);
        !           521:        else
        !           522:                dir[1] = self->s.angles[1] + 8 * (self->s.frame - FRAME_attak419);
        !           523:        dir[2] = 0;
        !           524: 
        !           525:        AngleVectors (dir, forward, NULL, NULL);
        !           526: 
        !           527:        monster_fire_bullet (self, start, forward, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
        !           528: }      
        !           529: 
        !           530: 
        !           531: mframe_t tank_frames_attack_blast [] =
        !           532: {
        !           533:        ai_charge, 0,   NULL,
        !           534:        ai_charge, 0,   NULL,
        !           535:        ai_charge, 0,   NULL,
        !           536:        ai_charge, 0,   NULL,
        !           537:        ai_charge, -1,  NULL,
        !           538:        ai_charge, -2,  NULL,
        !           539:        ai_charge, -1,  NULL,
        !           540:        ai_charge, -1,  NULL,
        !           541:        ai_charge, 0,   NULL,
        !           542:        ai_charge, 0,   TankBlaster,            // 10
        !           543:        ai_charge, 0,   NULL,
        !           544:        ai_charge, 0,   NULL,
        !           545:        ai_charge, 0,   TankBlaster,
        !           546:        ai_charge, 0,   NULL,
        !           547:        ai_charge, 0,   NULL,
        !           548:        ai_charge, 0,   TankBlaster                     // 16
        !           549: };
        !           550: mmove_t tank_move_attack_blast = {FRAME_attak101, FRAME_attak116, tank_frames_attack_blast, tank_reattack_blaster};
        !           551: 
        !           552: mframe_t tank_frames_reattack_blast [] =
        !           553: {
        !           554:        ai_charge, 0,   NULL,
        !           555:        ai_charge, 0,   NULL,
        !           556:        ai_charge, 0,   TankBlaster,
        !           557:        ai_charge, 0,   NULL,
        !           558:        ai_charge, 0,   NULL,
        !           559:        ai_charge, 0,   TankBlaster                     // 16
        !           560: };
        !           561: mmove_t tank_move_reattack_blast = {FRAME_attak111, FRAME_attak116, tank_frames_reattack_blast, tank_reattack_blaster};
        !           562: 
        !           563: mframe_t tank_frames_attack_post_blast [] =    
        !           564: {
        !           565:        ai_move, 0,             NULL,                           // 17
        !           566:        ai_move, 0,             NULL,
        !           567:        ai_move, 2,             NULL,
        !           568:        ai_move, 3,             NULL,
        !           569:        ai_move, 2,             NULL,
        !           570:        ai_move, -2,    tank_footstep           // 22
        !           571: };
        !           572: mmove_t tank_move_attack_post_blast = {FRAME_attak117, FRAME_attak122, tank_frames_attack_post_blast, tank_run};
        !           573: 
        !           574: void tank_reattack_blaster (edict_t *self)
        !           575: {
        !           576:        if (skill->value >= 2)
        !           577:                if (visible (self, self->enemy))
        !           578:                        if (self->enemy->health > 0)
        !           579:                                if (random() <= 0.6)
        !           580:                                {
        !           581:                                        self->monsterinfo.currentmove = &tank_move_reattack_blast;
        !           582:                                        return;
        !           583:                                }
        !           584:        self->monsterinfo.currentmove = &tank_move_attack_post_blast;
        !           585: }
        !           586: 
        !           587: 
        !           588: void tank_poststrike (edict_t *self)
        !           589: {
        !           590:        self->enemy = NULL;
        !           591:        tank_run (self);
        !           592: }
        !           593: 
        !           594: mframe_t tank_frames_attack_strike [] =
        !           595: {
        !           596:        ai_move, 3,   NULL,
        !           597:        ai_move, 2,   NULL,
        !           598:        ai_move, 2,   NULL,
        !           599:        ai_move, 1,   NULL,
        !           600:        ai_move, 6,   NULL,
        !           601:        ai_move, 7,   NULL,
        !           602:        ai_move, 9,   tank_footstep,
        !           603:        ai_move, 2,   NULL,
        !           604:        ai_move, 1,   NULL,
        !           605:        ai_move, 2,   NULL,
        !           606:        ai_move, 2,   tank_footstep,
        !           607:        ai_move, 2,   NULL,
        !           608:        ai_move, 0,   NULL,
        !           609:        ai_move, 0,   NULL,
        !           610:        ai_move, 0,   NULL,
        !           611:        ai_move, 0,   NULL,
        !           612:        ai_move, -2,  NULL,
        !           613:        ai_move, -2,  NULL,
        !           614:        ai_move, 0,   tank_windup,
        !           615:        ai_move, 0,   NULL,
        !           616:        ai_move, 0,   NULL,
        !           617:        ai_move, 0,   NULL,
        !           618:        ai_move, 0,   NULL,
        !           619:        ai_move, 0,   NULL,
        !           620:        ai_move, 0,   NULL,
        !           621:        ai_move, 0,   TankStrike,
        !           622:        ai_move, 0,   NULL,
        !           623:        ai_move, -1,  NULL,
        !           624:        ai_move, -1,  NULL,
        !           625:        ai_move, -1,  NULL,
        !           626:        ai_move, -1,  NULL,
        !           627:        ai_move, -1,  NULL,
        !           628:        ai_move, -3,  NULL,
        !           629:        ai_move, -10, NULL,
        !           630:        ai_move, -10, NULL,
        !           631:        ai_move, -2,  NULL,
        !           632:        ai_move, -3,  NULL,
        !           633:        ai_move, -2,  tank_footstep
        !           634: };
        !           635: mmove_t tank_move_attack_strike = {FRAME_attak201, FRAME_attak238, tank_frames_attack_strike, tank_poststrike};
        !           636: 
        !           637: mframe_t tank_frames_attack_pre_rocket [] =
        !           638: {
        !           639:        ai_charge, 0,  NULL,
        !           640:        ai_charge, 0,  NULL,
        !           641:        ai_charge, 0,  NULL,
        !           642:        ai_charge, 0,  NULL,
        !           643:        ai_charge, 0,  NULL,
        !           644:        ai_charge, 0,  NULL,
        !           645:        ai_charge, 0,  NULL,
        !           646:        ai_charge, 0,  NULL,
        !           647:        ai_charge, 0,  NULL,
        !           648:        ai_charge, 0,  NULL,                    // 10
        !           649: 
        !           650:        ai_charge, 0,  NULL,
        !           651:        ai_charge, 1,  NULL,
        !           652:        ai_charge, 2,  NULL,
        !           653:        ai_charge, 7,  NULL,
        !           654:        ai_charge, 7,  NULL,
        !           655:        ai_charge, 7,  tank_footstep,
        !           656:        ai_charge, 0,  NULL,
        !           657:        ai_charge, 0,  NULL,
        !           658:        ai_charge, 0,  NULL,
        !           659:        ai_charge, 0,  NULL,                    // 20
        !           660: 
        !           661:        ai_charge, -3, NULL
        !           662: };
        !           663: mmove_t tank_move_attack_pre_rocket = {FRAME_attak301, FRAME_attak321, tank_frames_attack_pre_rocket, tank_doattack_rocket};
        !           664: 
        !           665: mframe_t tank_frames_attack_fire_rocket [] =
        !           666: {
        !           667:        ai_charge, -3, NULL,                    // Loop Start   22 
        !           668:        ai_charge, 0,  NULL,
        !           669:        ai_charge, 0,  TankRocket,              // 24
        !           670:        ai_charge, 0,  NULL,
        !           671:        ai_charge, 0,  NULL,
        !           672:        ai_charge, 0,  TankRocket,
        !           673:        ai_charge, 0,  NULL,
        !           674:        ai_charge, 0,  NULL,
        !           675:        ai_charge, -1, TankRocket               // 30   Loop End
        !           676: };
        !           677: mmove_t tank_move_attack_fire_rocket = {FRAME_attak322, FRAME_attak330, tank_frames_attack_fire_rocket, tank_refire_rocket};
        !           678: 
        !           679: mframe_t tank_frames_attack_post_rocket [] =
        !           680: {      
        !           681:        ai_charge, 0,  NULL,                    // 31
        !           682:        ai_charge, -1, NULL,
        !           683:        ai_charge, -1, NULL,
        !           684:        ai_charge, 0,  NULL,
        !           685:        ai_charge, 2,  NULL,
        !           686:        ai_charge, 3,  NULL,
        !           687:        ai_charge, 4,  NULL,
        !           688:        ai_charge, 2,  NULL,
        !           689:        ai_charge, 0,  NULL,
        !           690:        ai_charge, 0,  NULL,                    // 40
        !           691: 
        !           692:        ai_charge, 0,  NULL,
        !           693:        ai_charge, -9, NULL,
        !           694:        ai_charge, -8, NULL,
        !           695:        ai_charge, -7, NULL,
        !           696:        ai_charge, -1, NULL,
        !           697:        ai_charge, -1, tank_footstep,
        !           698:        ai_charge, 0,  NULL,
        !           699:        ai_charge, 0,  NULL,
        !           700:        ai_charge, 0,  NULL,
        !           701:        ai_charge, 0,  NULL,                    // 50
        !           702: 
        !           703:        ai_charge, 0,  NULL,
        !           704:        ai_charge, 0,  NULL,
        !           705:        ai_charge, 0,  NULL
        !           706: };
        !           707: mmove_t tank_move_attack_post_rocket = {FRAME_attak331, FRAME_attak353, tank_frames_attack_post_rocket, tank_run};
        !           708: 
        !           709: mframe_t tank_frames_attack_chain [] =
        !           710: {
        !           711:        ai_charge, 0, NULL,
        !           712:        ai_charge, 0, NULL,
        !           713:        ai_charge, 0, NULL,
        !           714:        ai_charge, 0, NULL,
        !           715:        ai_charge, 0, NULL,
        !           716:        NULL,      0, TankMachineGun,
        !           717:        NULL,      0, TankMachineGun,
        !           718:        NULL,      0, TankMachineGun,
        !           719:        NULL,      0, TankMachineGun,
        !           720:        NULL,      0, TankMachineGun,
        !           721:        NULL,      0, TankMachineGun,
        !           722:        NULL,      0, TankMachineGun,
        !           723:        NULL,      0, TankMachineGun,
        !           724:        NULL,      0, TankMachineGun,
        !           725:        NULL,      0, TankMachineGun,
        !           726:        NULL,      0, TankMachineGun,
        !           727:        NULL,      0, TankMachineGun,
        !           728:        NULL,      0, TankMachineGun,
        !           729:        NULL,      0, TankMachineGun,
        !           730:        NULL,      0, TankMachineGun,
        !           731:        NULL,      0, TankMachineGun,
        !           732:        NULL,      0, TankMachineGun,
        !           733:        NULL,      0, TankMachineGun,
        !           734:        NULL,      0, TankMachineGun,
        !           735:        ai_charge, 0, NULL,
        !           736:        ai_charge, 0, NULL,
        !           737:        ai_charge, 0, NULL,
        !           738:        ai_charge, 0, NULL,
        !           739:        ai_charge, 0, NULL
        !           740: };
        !           741: mmove_t tank_move_attack_chain = {FRAME_attak401, FRAME_attak429, tank_frames_attack_chain, tank_run};
        !           742: 
        !           743: void tank_refire_rocket (edict_t *self)
        !           744: {
        !           745:        // PMM - blindfire cleanup
        !           746:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
        !           747:        {
        !           748:                self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
        !           749:                self->monsterinfo.currentmove = &tank_move_attack_post_rocket;
        !           750:                return;
        !           751:        }
        !           752:        // pmm
        !           753: 
        !           754:        // Only on hard or nightmare
        !           755:        if ( skill->value >= 2 )
        !           756:                if (self->enemy->health > 0)
        !           757:                        if (visible(self, self->enemy) )
        !           758:                                if (random() <= 0.4)
        !           759:                                {
        !           760:                                        self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
        !           761:                                        return;
        !           762:                                }
        !           763:        self->monsterinfo.currentmove = &tank_move_attack_post_rocket;
        !           764: }
        !           765: 
        !           766: void tank_doattack_rocket (edict_t *self)
        !           767: {
        !           768:        self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
        !           769: }
        !           770: 
        !           771: void tank_attack(edict_t *self)
        !           772: {
        !           773:        vec3_t  vec;
        !           774:        float   range;
        !           775:        float   r;
        !           776:        // PMM
        !           777:        float   chance;
        !           778: 
        !           779:        // PMM
        !           780:        if (!self->enemy || !self->enemy->inuse)
        !           781:                return;
        !           782: 
        !           783:        if (self->enemy->health < 0)
        !           784:        {
        !           785:                self->monsterinfo.currentmove = &tank_move_attack_strike;
        !           786:                self->monsterinfo.aiflags &= ~AI_BRUTAL;
        !           787:                return;
        !           788:        }
        !           789: 
        !           790:        // PMM 
        !           791:        if (self->monsterinfo.attack_state == AS_BLIND)
        !           792:        {
        !           793:                // setup shot probabilities
        !           794:                if (self->monsterinfo.blind_fire_delay < 1.0)
        !           795:                        chance = 1.0;
        !           796:                else if (self->monsterinfo.blind_fire_delay < 7.5)
        !           797:                        chance = 0.4;
        !           798:                else
        !           799:                        chance = 0.1;
        !           800: 
        !           801:                r = random();
        !           802: 
        !           803: //             gi.dprintf ("chance = %2.2f, roll = %2.2f\n", chance, r);
        !           804: 
        !           805:                self->monsterinfo.blind_fire_delay += 3.2 + 2.0 + random()*3.0;
        !           806: 
        !           807:                // don't shoot at the origin
        !           808:                if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin))
        !           809:                        return;
        !           810: 
        !           811:                // don't shoot if the dice say not to
        !           812:                if (r > chance)
        !           813:                {
        !           814: //                     if ((g_showlogic) && (g_showlogic->value))
        !           815: //                             gi.dprintf ("blindfire - NO SHOT\n");
        !           816:                        return;
        !           817:                }
        !           818: 
        !           819:                // turn on manual steering to signal both manual steering and blindfire
        !           820:                self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
        !           821:                self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
        !           822:                self->monsterinfo.attack_finished = level.time + 3.0 + 2*random();
        !           823:                self->pain_debounce_time = level.time + 5.0;    // no pain for a while
        !           824:                return;
        !           825:        }
        !           826:        // pmm
        !           827: 
        !           828:        VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
        !           829:        range = VectorLength (vec);
        !           830: 
        !           831:        r = random();
        !           832: 
        !           833:        if (range <= 125)
        !           834:        {
        !           835:                if (r < 0.4)
        !           836:                        self->monsterinfo.currentmove = &tank_move_attack_chain;
        !           837:                else 
        !           838:                        self->monsterinfo.currentmove = &tank_move_attack_blast;
        !           839:        }
        !           840:        else if (range <= 250)
        !           841:        {
        !           842:                if (r < 0.5)
        !           843:                        self->monsterinfo.currentmove = &tank_move_attack_chain;
        !           844:                else
        !           845:                        self->monsterinfo.currentmove = &tank_move_attack_blast;
        !           846:        }
        !           847:        else
        !           848:        {
        !           849:                if (r < 0.33)
        !           850:                        self->monsterinfo.currentmove = &tank_move_attack_chain;
        !           851:                else if (r < 0.66)
        !           852:                {
        !           853:                        self->monsterinfo.currentmove = &tank_move_attack_pre_rocket;
        !           854:                        self->pain_debounce_time = level.time + 5.0;    // no pain for a while
        !           855:                }
        !           856:                else
        !           857:                        self->monsterinfo.currentmove = &tank_move_attack_blast;
        !           858:        }
        !           859: }
        !           860: 
        !           861: 
        !           862: //
        !           863: // death
        !           864: //
        !           865: 
        !           866: void tank_dead (edict_t *self)
        !           867: {
        !           868:        VectorSet (self->mins, -16, -16, -16);
        !           869:        VectorSet (self->maxs, 16, 16, -0);
        !           870:        self->movetype = MOVETYPE_TOSS;
        !           871:        self->svflags |= SVF_DEADMONSTER;
        !           872:        self->nextthink = 0;
        !           873:        gi.linkentity (self);
        !           874: }
        !           875: 
        !           876: mframe_t tank_frames_death1 [] =
        !           877: {
        !           878:        ai_move, -7,  NULL,
        !           879:        ai_move, -2,  NULL,
        !           880:        ai_move, -2,  NULL,
        !           881:        ai_move, 1,   NULL,
        !           882:        ai_move, 3,   NULL,
        !           883:        ai_move, 6,   NULL,
        !           884:        ai_move, 1,   NULL,
        !           885:        ai_move, 1,   NULL,
        !           886:        ai_move, 2,   NULL,
        !           887:        ai_move, 0,   NULL,
        !           888:        ai_move, 0,   NULL,
        !           889:        ai_move, 0,   NULL,
        !           890:        ai_move, -2,  NULL,
        !           891:        ai_move, 0,   NULL,
        !           892:        ai_move, 0,   NULL,
        !           893:        ai_move, -3,  NULL,
        !           894:        ai_move, 0,   NULL,
        !           895:        ai_move, 0,   NULL,
        !           896:        ai_move, 0,   NULL,
        !           897:        ai_move, 0,   NULL,
        !           898:        ai_move, 0,   NULL,
        !           899:        ai_move, 0,   NULL,
        !           900:        ai_move, -4,  NULL,
        !           901:        ai_move, -6,  NULL,
        !           902:        ai_move, -4,  NULL,
        !           903:        ai_move, -5,  NULL,
        !           904:        ai_move, -7,  NULL,
        !           905:        ai_move, -15, tank_thud,
        !           906:        ai_move, -5,  NULL,
        !           907:        ai_move, 0,   NULL,
        !           908:        ai_move, 0,   NULL,
        !           909:        ai_move, 0,   NULL
        !           910: };
        !           911: mmove_t        tank_move_death = {FRAME_death101, FRAME_death132, tank_frames_death1, tank_dead};
        !           912: 
        !           913: void tank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
        !           914: {
        !           915:        int             n;
        !           916: 
        !           917: // check for gib
        !           918:        if (self->health <= self->gib_health)
        !           919:        {
        !           920:                gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
        !           921:                for (n= 0; n < 1 /*4*/; n++)
        !           922:                        ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
        !           923:                for (n= 0; n < 4; n++)
        !           924:                        ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
        !           925:                ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
        !           926:                ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
        !           927:                self->deadflag = DEAD_DEAD;
        !           928:                return;
        !           929:        }
        !           930: 
        !           931:        if (self->deadflag == DEAD_DEAD)
        !           932:                return;
        !           933: 
        !           934: // regular death
        !           935:        gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
        !           936:        self->deadflag = DEAD_DEAD;
        !           937:        self->takedamage = DAMAGE_YES;
        !           938: 
        !           939:        self->monsterinfo.currentmove = &tank_move_death;
        !           940:        
        !           941: }
        !           942: 
        !           943: //===========
        !           944: //PGM
        !           945: qboolean tank_blocked (edict_t *self, float dist)
        !           946: {
        !           947:        if(blocked_checkshot (self, 0.25 + (0.05 * skill->value) ))
        !           948:                return true;
        !           949: 
        !           950:        if(blocked_checkplat (self, dist))
        !           951:                return true;
        !           952: 
        !           953:        return false;
        !           954: }
        !           955: //PGM
        !           956: //===========
        !           957: 
        !           958: //
        !           959: // monster_tank
        !           960: //
        !           961: 
        !           962: /*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
        !           963: */
        !           964: /*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
        !           965: */
        !           966: void SP_monster_tank (edict_t *self)
        !           967: {
        !           968:        if (deathmatch->value)
        !           969:        {
        !           970:                G_FreeEdict (self);
        !           971:                return;
        !           972:        }
        !           973: 
        !           974:        self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
        !           975:        VectorSet (self->mins, -32, -32, -16);
        !           976:        VectorSet (self->maxs, 32, 32, 72);
        !           977:        self->movetype = MOVETYPE_STEP;
        !           978:        self->solid = SOLID_BBOX;
        !           979: 
        !           980:        sound_pain = gi.soundindex ("tank/tnkpain2.wav");
        !           981:        sound_thud = gi.soundindex ("tank/tnkdeth2.wav");
        !           982:        sound_idle = gi.soundindex ("tank/tnkidle1.wav");
        !           983:        sound_die = gi.soundindex ("tank/death.wav");
        !           984:        sound_step = gi.soundindex ("tank/step.wav");
        !           985:        sound_windup = gi.soundindex ("tank/tnkatck4.wav");
        !           986:        sound_strike = gi.soundindex ("tank/tnkatck5.wav");
        !           987:        sound_sight = gi.soundindex ("tank/sight1.wav");
        !           988: 
        !           989:        gi.soundindex ("tank/tnkatck1.wav");
        !           990:        gi.soundindex ("tank/tnkatk2a.wav");
        !           991:        gi.soundindex ("tank/tnkatk2b.wav");
        !           992:        gi.soundindex ("tank/tnkatk2c.wav");
        !           993:        gi.soundindex ("tank/tnkatk2d.wav");
        !           994:        gi.soundindex ("tank/tnkatk2e.wav");
        !           995:        gi.soundindex ("tank/tnkatck3.wav");
        !           996: 
        !           997:        if (strcmp(self->classname, "monster_tank_commander") == 0)
        !           998:        {
        !           999:                self->health = 1000;
        !          1000:                self->gib_health = -225;
        !          1001:        }
        !          1002:        else
        !          1003:        {
        !          1004:                self->health = 750;
        !          1005:                self->gib_health = -200;
        !          1006:        }
        !          1007: 
        !          1008:        self->mass = 500;
        !          1009: 
        !          1010:        self->pain = tank_pain;
        !          1011:        self->die = tank_die;
        !          1012:        self->monsterinfo.stand = tank_stand;
        !          1013:        self->monsterinfo.walk = tank_walk;
        !          1014:        self->monsterinfo.run = tank_run;
        !          1015:        self->monsterinfo.dodge = NULL;
        !          1016:        self->monsterinfo.attack = tank_attack;
        !          1017:        self->monsterinfo.melee = NULL;
        !          1018:        self->monsterinfo.sight = tank_sight;
        !          1019:        self->monsterinfo.idle = tank_idle;
        !          1020:        self->monsterinfo.blocked = tank_blocked;               // PGM
        !          1021: 
        !          1022:        gi.linkentity (self);
        !          1023:        
        !          1024:        self->monsterinfo.currentmove = &tank_move_stand;
        !          1025:        self->monsterinfo.scale = MODEL_SCALE;
        !          1026: 
        !          1027:        walkmonster_start(self);
        !          1028: 
        !          1029:        // PMM
        !          1030:        self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
        !          1031:        self->monsterinfo.blindfire = true;
        !          1032:        //pmm
        !          1033:        if (strcmp(self->classname, "monster_tank_commander") == 0)
        !          1034:                self->s.skinnum = 2;
        !          1035: }

unix.superglobalmegacorp.com

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