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