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

1.1       root        1: /*
                      2: ==============================================================================
                      3: 
                      4: GUNNER
                      5: 
                      6: ==============================================================================
                      7: */
                      8: 
                      9: #include "g_local.h"
                     10: #include "m_gunner.h"
                     11: 
                     12: 
                     13: static int     sound_pain;
                     14: static int     sound_pain2;
                     15: static int     sound_death;
                     16: static int     sound_idle;
                     17: static int     sound_open;
                     18: static int     sound_search;
                     19: static int     sound_sight;
                     20: 
                     21: void gunner_idlesound (edict_t *self)
                     22: {
                     23:        gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
                     24: }
                     25: 
                     26: void gunner_sight (edict_t *self, edict_t *other)
                     27: {
                     28:        gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
                     29: }
                     30: 
                     31: void gunner_search (edict_t *self)
                     32: {
                     33:        gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
                     34: }
                     35: 
                     36: 
                     37: qboolean visible (edict_t *self, edict_t *other);
                     38: void GunnerGrenade (edict_t *self);
                     39: void GunnerFire (edict_t *self);
                     40: void gunner_fire_chain(edict_t *self);
                     41: void gunner_refire_chain(edict_t *self);
                     42: 
                     43: 
                     44: void gunner_stand (edict_t *self);
                     45: 
                     46: mframe_t gunner_frames_fidget [] =
                     47: {
                     48:        ai_stand, 0, NULL,
                     49:        ai_stand, 0, NULL,
                     50:        ai_stand, 0, NULL,
                     51:        ai_stand, 0, NULL,
                     52:        ai_stand, 0, NULL,
                     53:        ai_stand, 0, NULL,
                     54:        ai_stand, 0, NULL,
                     55:        ai_stand, 0, gunner_idlesound,
                     56:        ai_stand, 0, NULL,
                     57: 
                     58:        ai_stand, 0, NULL,
                     59:        ai_stand, 0, NULL,
                     60:        ai_stand, 0, NULL,
                     61:        ai_stand, 0, NULL,
                     62:        ai_stand, 0, NULL,
                     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: 
                     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: 
                     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: 
                     91:        ai_stand, 0, NULL,
                     92:        ai_stand, 0, NULL,
                     93:        ai_stand, 0, NULL,
                     94:        ai_stand, 0, NULL,
                     95:        ai_stand, 0, NULL,
                     96:        ai_stand, 0, NULL,
                     97:        ai_stand, 0, NULL,
                     98:        ai_stand, 0, NULL,
                     99:        ai_stand, 0, NULL,
                    100:        ai_stand, 0, NULL
                    101: };
                    102: mmove_t        gunner_move_fidget = {FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand};
                    103: 
                    104: void gunner_fidget (edict_t *self)
                    105: {
                    106:        if (self->monsterinfo.aiflags & AI_STAND_GROUND)
                    107:                return;
                    108:        if (random() <= 0.05)
                    109:                self->monsterinfo.currentmove = &gunner_move_fidget;
                    110: }
                    111: 
                    112: mframe_t gunner_frames_stand [] =
                    113: {
                    114:        ai_stand, 0, NULL,
                    115:        ai_stand, 0, NULL,
                    116:        ai_stand, 0, NULL,
                    117:        ai_stand, 0, NULL,
                    118:        ai_stand, 0, NULL,
                    119:        ai_stand, 0, NULL,
                    120:        ai_stand, 0, NULL,
                    121:        ai_stand, 0, NULL,
                    122:        ai_stand, 0, NULL,
                    123:        ai_stand, 0, gunner_fidget,
                    124: 
                    125:        ai_stand, 0, NULL,
                    126:        ai_stand, 0, NULL,
                    127:        ai_stand, 0, NULL,
                    128:        ai_stand, 0, NULL,
                    129:        ai_stand, 0, NULL,
                    130:        ai_stand, 0, NULL,
                    131:        ai_stand, 0, NULL,
                    132:        ai_stand, 0, NULL,
                    133:        ai_stand, 0, NULL,
                    134:        ai_stand, 0, gunner_fidget,
                    135: 
                    136:        ai_stand, 0, NULL,
                    137:        ai_stand, 0, NULL,
                    138:        ai_stand, 0, NULL,
                    139:        ai_stand, 0, NULL,
                    140:        ai_stand, 0, NULL,
                    141:        ai_stand, 0, NULL,
                    142:        ai_stand, 0, NULL,
                    143:        ai_stand, 0, NULL,
                    144:        ai_stand, 0, NULL,
                    145:        ai_stand, 0, gunner_fidget
                    146: };
                    147: mmove_t        gunner_move_stand = {FRAME_stand01, FRAME_stand30, gunner_frames_stand, NULL};
                    148: 
                    149: void gunner_stand (edict_t *self)
                    150: {
                    151:                self->monsterinfo.currentmove = &gunner_move_stand;
                    152: }
                    153: 
                    154: 
                    155: mframe_t gunner_frames_walk [] =
                    156: {
                    157:        ai_walk, 0, NULL,
                    158:        ai_walk, 3, NULL,
                    159:        ai_walk, 4, NULL,
                    160:        ai_walk, 5, NULL,
                    161:        ai_walk, 7, NULL,
                    162:        ai_walk, 2, NULL,
                    163:        ai_walk, 6, NULL,
                    164:        ai_walk, 4, NULL,
                    165:        ai_walk, 2, NULL,
                    166:        ai_walk, 7, NULL,
                    167:        ai_walk, 5, NULL,
                    168:        ai_walk, 7, NULL,
                    169:        ai_walk, 4, NULL
                    170: };
                    171: mmove_t gunner_move_walk = {FRAME_walk07, FRAME_walk19, gunner_frames_walk, NULL};
                    172: 
                    173: void gunner_walk (edict_t *self)
                    174: {
                    175:        self->monsterinfo.currentmove = &gunner_move_walk;
                    176: }
                    177: 
                    178: mframe_t gunner_frames_run [] =
                    179: {
                    180:        ai_run, 26, NULL,
                    181:        ai_run, 9,  NULL,
                    182:        ai_run, 9,  NULL,
                    183:        ai_run, 9,  monster_done_dodge,
                    184:        ai_run, 15, NULL,
                    185:        ai_run, 10, NULL,
                    186:        ai_run, 13, NULL,
                    187:        ai_run, 6,  NULL
                    188: };
                    189: 
                    190: mmove_t gunner_move_run = {FRAME_run01, FRAME_run08, gunner_frames_run, NULL};
                    191: 
                    192: void gunner_run (edict_t *self)
                    193: {
                    194:        monster_done_dodge(self);
                    195:        if (self->monsterinfo.aiflags & AI_STAND_GROUND)
                    196:                self->monsterinfo.currentmove = &gunner_move_stand;
                    197:        else
                    198:                self->monsterinfo.currentmove = &gunner_move_run;
                    199: }
                    200: 
                    201: mframe_t gunner_frames_runandshoot [] =
                    202: {
                    203:        ai_run, 32, NULL,
                    204:        ai_run, 15, NULL,
                    205:        ai_run, 10, NULL,
                    206:        ai_run, 18, NULL,
                    207:        ai_run, 8,  NULL,
                    208:        ai_run, 20, NULL
                    209: };
                    210: 
                    211: mmove_t gunner_move_runandshoot = {FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, NULL};
                    212: 
                    213: void gunner_runandshoot (edict_t *self)
                    214: {
                    215:        self->monsterinfo.currentmove = &gunner_move_runandshoot;
                    216: }
                    217: 
                    218: mframe_t gunner_frames_pain3 [] =
                    219: {
                    220:        ai_move, -3, NULL,
                    221:        ai_move, 1,      NULL,
                    222:        ai_move, 1,      NULL,
                    223:        ai_move, 0,      NULL,
                    224:        ai_move, 1,      NULL
                    225: };
                    226: mmove_t gunner_move_pain3 = {FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run};
                    227: 
                    228: mframe_t gunner_frames_pain2 [] =
                    229: {
                    230:        ai_move, -2, NULL,
                    231:        ai_move, 11, NULL,
                    232:        ai_move, 6,      NULL,
                    233:        ai_move, 2,      NULL,
                    234:        ai_move, -1, NULL,
                    235:        ai_move, -7, NULL,
                    236:        ai_move, -2, NULL,
                    237:        ai_move, -7, NULL
                    238: };
                    239: mmove_t gunner_move_pain2 = {FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run};
                    240: 
                    241: mframe_t gunner_frames_pain1 [] =
                    242: {
                    243:        ai_move, 2,      NULL,
                    244:        ai_move, 0,      NULL,
                    245:        ai_move, -5, NULL,
                    246:        ai_move, 3,      NULL,
                    247:        ai_move, -1, NULL,
                    248:        ai_move, 0,      NULL,
                    249:        ai_move, 0,      NULL,
                    250:        ai_move, 0,      NULL,
                    251:        ai_move, 0,      NULL,
                    252:        ai_move, 1,      NULL,
                    253:        ai_move, 1,      NULL,
                    254:        ai_move, 2,      NULL,
                    255:        ai_move, 1,      NULL,
                    256:        ai_move, 0,      NULL,
                    257:        ai_move, -2, NULL,
                    258:        ai_move, -2, NULL,
                    259:        ai_move, 0,      NULL,
                    260:        ai_move, 0,      NULL
                    261: };
                    262: mmove_t gunner_move_pain1 = {FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run};
                    263: 
                    264: void gunner_pain (edict_t *self, edict_t *other, float kick, int damage)
                    265: {
                    266:        if (self->health < (self->max_health / 2))
                    267:                self->s.skinnum = 1;
                    268: 
                    269:        monster_done_dodge (self);
                    270: 
                    271:        if (!self->groundentity)
                    272:        {
                    273:                if ((g_showlogic) && (g_showlogic->value))
                    274:                        gi.dprintf ("gunner: pain avoided due to no ground\n");
                    275:                return;
                    276:        }
                    277: 
                    278:        if (level.time < self->pain_debounce_time)
                    279:                return;
                    280: 
                    281:        self->pain_debounce_time = level.time + 3;
                    282: 
                    283:        if (rand()&1)
                    284:                gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
                    285:        else
                    286:                gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
                    287: 
                    288:        if (skill->value == 3)
                    289:                return;         // no pain anims in nightmare
                    290: 
                    291:        if (damage <= 10)
                    292:                self->monsterinfo.currentmove = &gunner_move_pain3;
                    293:        else if (damage <= 25)
                    294:                self->monsterinfo.currentmove = &gunner_move_pain2;
                    295:        else
                    296:                self->monsterinfo.currentmove = &gunner_move_pain1;
                    297: 
                    298:        self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
                    299: 
                    300:        // PMM - clear duck flag
                    301:        if (self->monsterinfo.aiflags & AI_DUCKED)
                    302:                monster_duck_up(self);
                    303: }
                    304: 
                    305: void gunner_dead (edict_t *self)
                    306: {
                    307:        VectorSet (self->mins, -16, -16, -24);
                    308:        VectorSet (self->maxs, 16, 16, -8);
                    309:        self->movetype = MOVETYPE_TOSS;
                    310:        self->svflags |= SVF_DEADMONSTER;
                    311:        self->nextthink = 0;
                    312:        gi.linkentity (self);
                    313: }
                    314: 
                    315: mframe_t gunner_frames_death [] =
                    316: {
                    317:        ai_move, 0,      NULL,
                    318:        ai_move, 0,      NULL,
                    319:        ai_move, 0,      NULL,
                    320:        ai_move, -7, NULL,
                    321:        ai_move, -3, NULL,
                    322:        ai_move, -5, NULL,
                    323:        ai_move, 8,      NULL,
                    324:        ai_move, 6,      NULL,
                    325:        ai_move, 0,      NULL,
                    326:        ai_move, 0,      NULL,
                    327:        ai_move, 0,      NULL
                    328: };
                    329: mmove_t gunner_move_death = {FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead};
                    330: 
                    331: void gunner_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                    332: {
                    333:        int             n;
                    334: 
                    335: // check for gib
                    336:        if (self->health <= self->gib_health)
                    337:        {
                    338:                gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
                    339:                for (n= 0; n < 2; n++)
                    340:                        ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
                    341:                for (n= 0; n < 4; n++)
                    342:                        ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
                    343:                ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
                    344:                self->deadflag = DEAD_DEAD;
                    345:                return;
                    346:        }
                    347: 
                    348:        if (self->deadflag == DEAD_DEAD)
                    349:                return;
                    350: 
                    351: // regular death
                    352:        gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
                    353:        self->deadflag = DEAD_DEAD;
                    354:        self->takedamage = DAMAGE_YES;
                    355:        self->monsterinfo.currentmove = &gunner_move_death;
                    356: }
                    357: 
                    358: // PMM - changed to duck code for new dodge
                    359: 
                    360: //
                    361: // this is specific to the gunner, leave it be
                    362: //
                    363: void gunner_duck_down (edict_t *self)
                    364: {
                    365: //     if (self->monsterinfo.aiflags & AI_DUCKED)
                    366: //             return;
                    367:        self->monsterinfo.aiflags |= AI_DUCKED;
                    368:        if (skill->value >= 2)
                    369:        {
                    370:                if (random() > 0.5)
                    371:                        GunnerGrenade (self);
                    372:        }
                    373: 
                    374: //     self->maxs[2] -= 32;
                    375:        self->maxs[2] = self->monsterinfo.base_height - 32;
                    376:        self->takedamage = DAMAGE_YES;
                    377:        if (self->monsterinfo.duck_wait_time < level.time)
                    378:                self->monsterinfo.duck_wait_time = level.time + 1;
                    379:        gi.linkentity (self);
                    380: }
                    381: 
                    382: mframe_t gunner_frames_duck [] =
                    383: {
                    384:        ai_move, 1,  gunner_duck_down,
                    385:        ai_move, 1,  NULL,
                    386:        ai_move, 1,  monster_duck_hold,
                    387:        ai_move, 0,  NULL,
                    388:        ai_move, -1, NULL,
                    389:        ai_move, -1, NULL,
                    390:        ai_move, 0,  monster_duck_up,
                    391:        ai_move, -1, NULL
                    392: };
                    393: mmove_t        gunner_move_duck = {FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run};
                    394: 
                    395: // PMM - gunner dodge moved below so I know about attack sequences
                    396: 
                    397: void gunner_opengun (edict_t *self)
                    398: {
                    399:        gi.sound (self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0);
                    400: }
                    401: 
                    402: void GunnerFire (edict_t *self)
                    403: {
                    404:        vec3_t  start;
                    405:        vec3_t  forward, right;
                    406:        vec3_t  target;
                    407:        vec3_t  aim;
                    408:        int             flash_number;
                    409: 
                    410:        if(!self->enemy || !self->enemy->inuse)         //PGM
                    411:                return;                                                                 //PGM
                    412: 
                    413:        flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216);
                    414: 
                    415:        AngleVectors (self->s.angles, forward, right, NULL);
                    416:        G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
                    417: 
                    418:        // project enemy back a bit and target there
                    419:        VectorCopy (self->enemy->s.origin, target);
                    420:        VectorMA (target, -0.2, self->enemy->velocity, target);
                    421:        target[2] += self->enemy->viewheight;
                    422: 
                    423:        VectorSubtract (target, start, aim);
                    424:        VectorNormalize (aim);
                    425:        monster_fire_bullet (self, start, aim, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
                    426: }
                    427: 
                    428: qboolean gunner_grenade_check(edict_t *self)
                    429: {
                    430:        vec3_t          start;
                    431:        vec3_t          forward, right;
                    432:        trace_t         tr;
                    433:        vec3_t          target, dir;
                    434: 
                    435:        if(!self->enemy)
                    436:                return false;
                    437: 
                    438:        // if the player is above my head, use machinegun.
                    439: 
                    440:        // check for flag telling us that we're blindfiring
                    441:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
                    442:        {
                    443:                if (self->s.origin[2]+self->viewheight < self->monsterinfo.blind_fire_target[2])
                    444:                {
                    445:                        if(g_showlogic && g_showlogic->value)
                    446:                                gi.dprintf("blind_fire_target is above my head, using machinegun\n");
                    447:                        return false;
                    448:                }
                    449:        }
                    450:        else if(self->absmax[2] <= self->enemy->absmin[2])
                    451:        {
                    452:                if(g_showlogic && g_showlogic->value)
                    453:                        gi.dprintf("player is above my head, using machinegun\n");
                    454:                return false;
                    455:        }
                    456: 
                    457:        // check to see that we can trace to the player before we start
                    458:        // tossing grenades around.
                    459:        AngleVectors (self->s.angles, forward, right, NULL);
                    460:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_GUNNER_GRENADE_1], forward, right, start);
                    461: 
                    462:        // pmm - check for blindfire flag
                    463:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
                    464:                VectorCopy (self->monsterinfo.blind_fire_target, target);
                    465:        else
                    466:                VectorCopy (self->enemy->s.origin, target);
                    467: 
                    468:        // see if we're too close
                    469:        VectorSubtract (self->s.origin, target, dir);
                    470: 
                    471:        if (VectorLength(dir) < 100)
                    472:                return false;
                    473: 
                    474:        tr = gi.trace(start, vec3_origin, vec3_origin, target, self, MASK_SHOT);
                    475:        if(tr.ent == self->enemy || tr.fraction == 1)
                    476:                return true;
                    477: 
                    478:        if(g_showlogic && g_showlogic->value)
                    479:                gi.dprintf("can't trace to target, using machinegun\n");
                    480:        return false;
                    481: }
                    482: 
                    483: void GunnerGrenade (edict_t *self)
                    484: {
                    485:        vec3_t  start;
                    486:        vec3_t  forward, right, up;
                    487:        vec3_t  aim;
                    488:        int             flash_number;
                    489:        float   spread;
                    490:        float   pitch;
                    491:        // PMM
                    492:        vec3_t  target; 
                    493:        qboolean blindfire;
                    494: 
                    495:        if(!self->enemy || !self->enemy->inuse)         //PGM
                    496:                return;                                                                 //PGM
                    497: 
                    498:        // pmm
                    499:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
                    500:                blindfire = true;
                    501: 
                    502:        if (self->s.frame == FRAME_attak105)
                    503:        {
                    504:                spread = .02;
                    505:                flash_number = MZ2_GUNNER_GRENADE_1;
                    506:        }
                    507:        else if (self->s.frame == FRAME_attak108)
                    508:        {
                    509:                spread = .05;
                    510:                flash_number = MZ2_GUNNER_GRENADE_2;
                    511:        }
                    512:        else if (self->s.frame == FRAME_attak111)
                    513:        {
                    514:                spread = .08;
                    515:                flash_number = MZ2_GUNNER_GRENADE_3;
                    516:        }
                    517:        else // (self->s.frame == FRAME_attak114)
                    518:        {
                    519:                self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
                    520:                spread = .11;
                    521:                flash_number = MZ2_GUNNER_GRENADE_4;
                    522:        }
                    523: 
                    524:        //      pmm
                    525:        // if we're shooting blind and we still can't see our enemy
                    526:        if ((blindfire) && (!visible(self, self->enemy)))
                    527:        {
                    528:                // and we have a valid blind_fire_target
                    529:                if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin))
                    530:                        return;
                    531:                
                    532: //             gi.dprintf ("blind_fire_target = %s\n", vtos (self->monsterinfo.blind_fire_target));
                    533: //             gi.dprintf ("GunnerGrenade: ideal yaw is %f\n", self->ideal_yaw);
                    534:                VectorCopy (self->monsterinfo.blind_fire_target, target);
                    535:        }
                    536:        else
                    537:                VectorCopy (self->s.origin, target);
                    538:        // pmm
                    539: 
                    540:        AngleVectors (self->s.angles, forward, right, up);      //PGM
                    541:        G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
                    542: 
                    543: //PGM
                    544:        if(self->enemy)
                    545:        {
                    546:                float   dist;
                    547: 
                    548: //             VectorSubtract(self->enemy->s.origin, self->s.origin, aim);
                    549:                VectorSubtract(target, self->s.origin, aim);
                    550:                dist = VectorLength(aim);
                    551: 
                    552:                // aim up if they're on the same level as me and far away.
                    553:                if((dist > 512) && (aim[2] < 64) && (aim[2] > -64))
                    554:                {
                    555:                        aim[2] += (dist - 512);
                    556:                }
                    557: 
                    558:                VectorNormalize (aim);
                    559:                pitch = aim[2];
                    560:                if(pitch > 0.4)
                    561:                {
                    562:                        pitch = 0.4;
                    563:                }
                    564:                else if(pitch < -0.5)
                    565:                        pitch = -0.5;
                    566:        }
                    567: //PGM
                    568: 
                    569:        //FIXME : do a spread -225 -75 75 225 degrees around forward
                    570: //     VectorCopy (forward, aim);
                    571:        VectorMA (forward, spread, right, aim);
                    572:        VectorMA (aim, pitch, up, aim);
                    573: 
                    574:        monster_fire_grenade (self, start, aim, 50, 600, flash_number);
                    575: }
                    576: 
                    577: mframe_t gunner_frames_attack_chain [] =
                    578: {
                    579:        /*
                    580:        ai_charge, 0, NULL,
                    581:        ai_charge, 0, NULL,
                    582:        ai_charge, 0, NULL,
                    583:        ai_charge, 0, NULL,
                    584:        ai_charge, 0, NULL,
                    585:        ai_charge, 0, NULL,
                    586:        ai_charge, 0, NULL,
                    587:        ai_charge, 0, NULL,
                    588:        */
                    589:        ai_charge, 0, gunner_opengun,
                    590:        ai_charge, 0, NULL,
                    591:        ai_charge, 0, NULL,
                    592:        ai_charge, 0, NULL,
                    593:        ai_charge, 0, NULL,
                    594:        ai_charge, 0, NULL,
                    595:        ai_charge, 0, NULL
                    596: };
                    597: mmove_t gunner_move_attack_chain = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain};
                    598: 
                    599: mframe_t gunner_frames_fire_chain [] =
                    600: {
                    601:        ai_charge,   0, GunnerFire,
                    602:        ai_charge,   0, GunnerFire,
                    603:        ai_charge,   0, GunnerFire,
                    604:        ai_charge,   0, GunnerFire,
                    605:        ai_charge,   0, GunnerFire,
                    606:        ai_charge,   0, GunnerFire,
                    607:        ai_charge,   0, GunnerFire,
                    608:        ai_charge,   0, GunnerFire
                    609: };
                    610: mmove_t gunner_move_fire_chain = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain};
                    611: 
                    612: mframe_t gunner_frames_endfire_chain [] =
                    613: {
                    614:        ai_charge, 0, NULL,
                    615:        ai_charge, 0, NULL,
                    616:        ai_charge, 0, NULL,
                    617:        ai_charge, 0, NULL,
                    618:        ai_charge, 0, NULL,
                    619:        ai_charge, 0, NULL,
                    620:        ai_charge, 0, NULL
                    621: };
                    622: mmove_t gunner_move_endfire_chain = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run};
                    623: 
                    624: void gunner_blind_check (edict_t *self)
                    625: {
                    626:        vec3_t  aim;
                    627: 
                    628:        if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
                    629:        {
                    630:                VectorSubtract(self->monsterinfo.blind_fire_target, self->s.origin, aim);
                    631:                self->ideal_yaw = vectoyaw(aim);
                    632:                
                    633: //             gi.dprintf ("blind_fire_target = %s\n", vtos (self->monsterinfo.blind_fire_target));
                    634: //             gi.dprintf ("gunner_attack: ideal yaw is %f\n", self->ideal_yaw);
                    635:        }
                    636: }
                    637: 
                    638: mframe_t gunner_frames_attack_grenade [] =
                    639: {
                    640:        ai_charge, 0, gunner_blind_check,
                    641:        ai_charge, 0, NULL,
                    642:        ai_charge, 0, NULL,
                    643:        ai_charge, 0, NULL,
                    644:        ai_charge, 0, GunnerGrenade,
                    645:        ai_charge, 0, NULL,
                    646:        ai_charge, 0, NULL,
                    647:        ai_charge, 0, GunnerGrenade,
                    648:        ai_charge, 0, NULL,
                    649:        ai_charge, 0, NULL,
                    650:        ai_charge, 0, GunnerGrenade,
                    651:        ai_charge, 0, NULL,
                    652:        ai_charge, 0, NULL,
                    653:        ai_charge, 0, GunnerGrenade,
                    654:        ai_charge, 0, NULL,
                    655:        ai_charge, 0, NULL,
                    656:        ai_charge, 0, NULL,
                    657:        ai_charge, 0, NULL,
                    658:        ai_charge, 0, NULL,
                    659:        ai_charge, 0, NULL,
                    660:        ai_charge, 0, NULL
                    661: };
                    662: mmove_t gunner_move_attack_grenade = {FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run};
                    663: 
                    664: void gunner_attack(edict_t *self)
                    665: {
                    666:        float chance, r;
                    667: 
                    668:        monster_done_dodge(self);
                    669: 
                    670:        // PMM 
                    671:        if (self->monsterinfo.attack_state == AS_BLIND)
                    672:        {
                    673:                // setup shot probabilities
                    674:                if (self->monsterinfo.blind_fire_delay < 1.0)
                    675:                        chance = 1.0;
                    676:                else if (self->monsterinfo.blind_fire_delay < 7.5)
                    677:                        chance = 0.4;
                    678:                else
                    679:                        chance = 0.1;
                    680: 
                    681:                r = random();
                    682: 
                    683: //             gi.dprintf ("chance = %2.2f, roll = %2.2f\n", chance, r);
                    684: 
                    685:                // minimum of 2 seconds, plus 0-3, after the shots are done
                    686:                self->monsterinfo.blind_fire_delay += 2.1 + 2.0 + random()*3.0;
                    687: 
                    688:                // don't shoot at the origin
                    689:                if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin))
                    690:                        return;
                    691: 
                    692:                // don't shoot if the dice say not to
                    693:                if (r > chance)
                    694:                {
                    695: //                     if ((g_showlogic) && (g_showlogic->value))
                    696: //                             gi.dprintf ("blindfire - NO SHOT\n");
                    697:                        return;
                    698:                }
                    699: 
                    700:                // turn on manual steering to signal both manual steering and blindfire
                    701:                self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
                    702:                if (gunner_grenade_check(self))
                    703:                {
                    704:                        self->monsterinfo.currentmove = &gunner_move_attack_grenade;
                    705:                        self->monsterinfo.attack_finished = level.time + 2*random();
                    706:                        return;
                    707:                }
                    708:                // pmm - should this be active?
                    709: //             else
                    710: //                     self->monsterinfo.currentmove = &gunner_move_attack_chain;
                    711: //             if ((g_showlogic) && (g_showlogic->value))
                    712: //                     gi.dprintf ("blind grenade check failed, doing nothing\n");
                    713: 
                    714:                // turn off blindfire flag
                    715:                self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
                    716:                return;
                    717:        }
                    718:        // pmm
                    719: 
                    720:        // PGM - gunner needs to use his chaingun if he's being attacked by a tesla.
                    721:        if ((range (self, self->enemy) == RANGE_MELEE) || self->bad_area)
                    722:        {
                    723:                self->monsterinfo.currentmove = &gunner_move_attack_chain;
                    724:        }
                    725:        else
                    726:        {
                    727:                if (random() <= 0.5 && gunner_grenade_check(self))
                    728:                        self->monsterinfo.currentmove = &gunner_move_attack_grenade;
                    729:                else
                    730:                        self->monsterinfo.currentmove = &gunner_move_attack_chain;
                    731:        }
                    732: }
                    733: 
                    734: void gunner_fire_chain(edict_t *self)
                    735: {
                    736:        self->monsterinfo.currentmove = &gunner_move_fire_chain;
                    737: }
                    738: 
                    739: void gunner_refire_chain(edict_t *self)
                    740: {
                    741:        if (self->enemy->health > 0)
                    742:                if ( visible (self, self->enemy) )
                    743:                        if (random() <= 0.5)
                    744:                        {
                    745:                                self->monsterinfo.currentmove = &gunner_move_fire_chain;
                    746:                                return;
                    747:                        }
                    748:        self->monsterinfo.currentmove = &gunner_move_endfire_chain;
                    749: }
                    750: /*
                    751: void gunner_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
                    752: {
                    753: // original quake2 dodge code
                    754: 
                    755:        if (random() > 0.25)
                    756:                return;
                    757: 
                    758:        if (!self->enemy)
                    759:                self->enemy = attacker;
                    760: 
                    761:        self->monsterinfo.currentmove = &gunner_move_duck;
                    762: 
                    763: //===========
                    764: //PMM - rogue rewrite of gunner dodge code.
                    765:        float   r;
                    766:        float   height;
                    767:        int             shooting = 0;
                    768: 
                    769:        if (!self->enemy)
                    770:        {
                    771:                self->enemy = attacker;
                    772:                FoundTarget (self);
                    773:        }
                    774: 
                    775:        // PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was
                    776:        // seeing numbers like 13 and 14)
                    777:        if ((eta < 0.1) || (eta > 5))
                    778:                return;
                    779: 
                    780:        r = random();
                    781:        if (r > (0.25*((skill->value)+1)))
                    782:                return;
                    783: 
                    784:        if ((self->monsterinfo.currentmove == &gunner_move_attack_chain) ||
                    785:                (self->monsterinfo.currentmove == &gunner_move_fire_chain) ||
                    786:                (self->monsterinfo.currentmove == &gunner_move_attack_grenade)
                    787:                )
                    788:        {
                    789:                shooting = 1;
                    790:        }
                    791:        if (self->monsterinfo.aiflags & AI_DODGING)
                    792:        {
                    793:                height = self->absmax[2];
                    794:        }
                    795:        else
                    796:        {
                    797:                height = self->absmax[2]-32-1;  // the -1 is because the absmax is s.origin + maxs + 1
                    798:        }
                    799: 
                    800:        // check to see if it makes sense to duck
                    801:        if (tr->endpos[2] <= height)
                    802:        {
                    803:                vec3_t right, diff;
                    804:                if (shooting)
                    805:                {
                    806:                        self->monsterinfo.attack_state = AS_SLIDING;
                    807:                        return;
                    808:                }
                    809:                AngleVectors (self->s.angles, NULL, right, NULL);
                    810:                VectorSubtract (tr->endpos, self->s.origin, diff);
                    811:                if (DotProduct (right, diff) < 0)
                    812:                {
                    813:                        self->monsterinfo.lefty = 1;
                    814:                }
                    815:                // if it doesn't sense to duck, try to strafe away
                    816:                monster_done_dodge (self);
                    817:                self->monsterinfo.currentmove = &gunner_move_run;
                    818:                self->monsterinfo.attack_state = AS_SLIDING;
                    819:                return;
                    820:        }
                    821: 
                    822:        if (skill->value == 0)
                    823:        {
                    824:                self->monsterinfo.currentmove = &gunner_move_duck;
                    825:                // PMM - stupid dodge
                    826:                self->monsterinfo.duck_wait_time = level.time + eta + 1;
                    827:                self->monsterinfo.aiflags |= AI_DODGING;
                    828:                return;
                    829:        }
                    830: 
                    831:        if (!shooting)
                    832:        {
                    833:                self->monsterinfo.currentmove = &gunner_move_duck;
                    834:                self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
                    835:                self->monsterinfo.aiflags |= AI_DODGING;
                    836:        }
                    837:        return;
                    838: //PMM
                    839: //===========
                    840: }
                    841: */
                    842: //===========
                    843: //PGM
                    844: void gunner_jump_now (edict_t *self)
                    845: {
                    846:        vec3_t  forward,up;
                    847: 
                    848:        AngleVectors (self->s.angles, forward, NULL, up);
                    849:        VectorMA(self->velocity, 100, forward, self->velocity);
                    850:        VectorMA(self->velocity, 300, up, self->velocity);
                    851: }
                    852: 
                    853: void gunner_jump2_now (edict_t *self)
                    854: {
                    855:        vec3_t  forward,up;
                    856: 
                    857:        AngleVectors (self->s.angles, forward, NULL, up);
                    858:        VectorMA(self->velocity, 150, forward, self->velocity);
                    859:        VectorMA(self->velocity, 400, up, self->velocity);
                    860: }
                    861: 
                    862: void gunner_jump_wait_land (edict_t *self)
                    863: {
                    864:        if(self->groundentity == NULL)
                    865:                self->monsterinfo.nextframe = self->s.frame;
                    866:        else 
                    867:                self->monsterinfo.nextframe = self->s.frame + 1;
                    868: }
                    869: 
                    870: mframe_t gunner_frames_jump [] =
                    871: {
                    872:        ai_move, 0, NULL,
                    873:        ai_move, 0, NULL,
                    874:        ai_move, 0, NULL,
                    875:        ai_move, 0, gunner_jump_now,
                    876:        ai_move, 0, NULL,
                    877:        ai_move, 0, NULL,
                    878:        ai_move, 0, gunner_jump_wait_land,
                    879:        ai_move, 0, NULL,
                    880:        ai_move, 0, NULL,
                    881:        ai_move, 0, NULL
                    882: };
                    883: mmove_t gunner_move_jump = { FRAME_jump01, FRAME_jump10, gunner_frames_jump, gunner_run };
                    884: 
                    885: mframe_t gunner_frames_jump2 [] =
                    886: {
                    887:        ai_move, -8, NULL,
                    888:        ai_move, -4, NULL,
                    889:        ai_move, -4, NULL,
                    890:        ai_move, 0, gunner_jump_now,
                    891:        ai_move, 0, NULL,
                    892:        ai_move, 0, NULL,
                    893:        ai_move, 0, gunner_jump_wait_land,
                    894:        ai_move, 0, NULL,
                    895:        ai_move, 0, NULL,
                    896:        ai_move, 0, NULL
                    897: };
                    898: mmove_t gunner_move_jump2 = { FRAME_jump01, FRAME_jump10, gunner_frames_jump2, gunner_run };
                    899: 
                    900: void gunner_jump (edict_t *self)
                    901: {
                    902:        if(!self->enemy)
                    903:                return;
                    904: 
                    905:        monster_done_dodge (self);
                    906: 
                    907:        if(self->enemy->s.origin[2] > self->s.origin[2])
                    908:                self->monsterinfo.currentmove = &gunner_move_jump2;
                    909:        else
                    910:                self->monsterinfo.currentmove = &gunner_move_jump;
                    911: }
                    912: 
                    913: //===========
                    914: //PGM
                    915: qboolean gunner_blocked (edict_t *self, float dist)
                    916: {
                    917:        if(blocked_checkshot (self, 0.25 + (0.05 * skill->value) ))
                    918:                return true;
                    919: 
                    920:        if(blocked_checkplat (self, dist))
                    921:                return true;
                    922: 
                    923:        if(blocked_checkjump (self, dist, 192, 40))
                    924:        {
                    925:                gunner_jump(self);
                    926:                return true;
                    927:        }
                    928: 
                    929:        return false;
                    930: }
                    931: //PGM
                    932: //===========
                    933: 
                    934: // PMM - new duck code
                    935: void gunner_duck (edict_t *self, float eta)
                    936: {
                    937:        if ((self->monsterinfo.currentmove == &gunner_move_jump2) ||
                    938:                (self->monsterinfo.currentmove == &gunner_move_jump))
                    939:        {
                    940:                return;
                    941:        }
                    942: 
                    943:        if ((self->monsterinfo.currentmove == &gunner_move_attack_chain) ||
                    944:                (self->monsterinfo.currentmove == &gunner_move_fire_chain) ||
                    945:                (self->monsterinfo.currentmove == &gunner_move_attack_grenade)
                    946:                )
                    947:        {
                    948:                // if we're shooting, and not on easy, don't dodge
                    949:                if (skill->value)
                    950:                {
                    951:                        self->monsterinfo.aiflags &= ~AI_DUCKED;
                    952:                        return;
                    953:                }
                    954:        }
                    955: 
                    956:        if (skill->value == 0)
                    957:                // PMM - stupid dodge
                    958:                self->monsterinfo.duck_wait_time = level.time + eta + 1;
                    959:        else
                    960:                self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
                    961: 
                    962:        // has to be done immediately otherwise he can get stuck
                    963:        gunner_duck_down(self);
                    964: 
                    965:        self->monsterinfo.nextframe = FRAME_duck01;
                    966:        self->monsterinfo.currentmove = &gunner_move_duck;
                    967:        return;
                    968: }
                    969: 
                    970: void gunner_sidestep (edict_t *self)
                    971: {
                    972:        if ((self->monsterinfo.currentmove == &gunner_move_jump2) ||
                    973:                (self->monsterinfo.currentmove == &gunner_move_jump))
                    974:        {
                    975:                return;
                    976:        }
                    977: 
                    978:        if ((self->monsterinfo.currentmove == &gunner_move_attack_chain) ||
                    979:                (self->monsterinfo.currentmove == &gunner_move_fire_chain) ||
                    980:                (self->monsterinfo.currentmove == &gunner_move_attack_grenade)
                    981:                )
                    982:        {
                    983:                // if we're shooting, and not on easy, don't dodge
                    984:                if (skill->value)
                    985:                {
                    986:                        self->monsterinfo.aiflags &= ~AI_DODGING;
                    987:                        return;
                    988:                }
                    989:        }
                    990: 
                    991:        if (self->monsterinfo.currentmove != &gunner_move_run)
                    992:                self->monsterinfo.currentmove = &gunner_move_run;
                    993: }
                    994: 
                    995: 
                    996: /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
                    997: */
                    998: void SP_monster_gunner (edict_t *self)
                    999: {
                   1000:        if (deathmatch->value)
                   1001:        {
                   1002:                G_FreeEdict (self);
                   1003:                return;
                   1004:        }
                   1005: 
                   1006:        sound_death = gi.soundindex ("gunner/death1.wav");      
                   1007:        sound_pain = gi.soundindex ("gunner/gunpain2.wav");     
                   1008:        sound_pain2 = gi.soundindex ("gunner/gunpain1.wav");    
                   1009:        sound_idle = gi.soundindex ("gunner/gunidle1.wav");     
                   1010:        sound_open = gi.soundindex ("gunner/gunatck1.wav");     
                   1011:        sound_search = gi.soundindex ("gunner/gunsrch1.wav");   
                   1012:        sound_sight = gi.soundindex ("gunner/sight1.wav");      
                   1013: 
                   1014:        gi.soundindex ("gunner/gunatck2.wav");
                   1015:        gi.soundindex ("gunner/gunatck3.wav");
                   1016: 
                   1017:        self->movetype = MOVETYPE_STEP;
                   1018:        self->solid = SOLID_BBOX;
                   1019:        self->s.modelindex = gi.modelindex ("models/monsters/gunner/tris.md2");
                   1020:        VectorSet (self->mins, -16, -16, -24);
                   1021:        VectorSet (self->maxs, 16, 16, 32);
                   1022: 
                   1023:        self->health = 175;
                   1024:        self->gib_health = -70;
                   1025:        self->mass = 200;
                   1026: 
                   1027:        self->pain = gunner_pain;
                   1028:        self->die = gunner_die;
                   1029: 
                   1030:        self->monsterinfo.stand = gunner_stand;
                   1031:        self->monsterinfo.walk = gunner_walk;
                   1032:        self->monsterinfo.run = gunner_run;
                   1033:        // pmm
                   1034:        self->monsterinfo.dodge = M_MonsterDodge;
                   1035:        self->monsterinfo.duck = gunner_duck;
                   1036:        self->monsterinfo.unduck = monster_duck_up;
                   1037:        self->monsterinfo.sidestep = gunner_sidestep;
                   1038: //     self->monsterinfo.dodge = gunner_dodge;
                   1039:        // pmm
                   1040:        self->monsterinfo.attack = gunner_attack;
                   1041:        self->monsterinfo.melee = NULL;
                   1042:        self->monsterinfo.sight = gunner_sight;
                   1043:        self->monsterinfo.search = gunner_search;
                   1044:        self->monsterinfo.blocked = gunner_blocked;             //PGM
                   1045: 
                   1046:        gi.linkentity (self);
                   1047: 
                   1048:        self->monsterinfo.currentmove = &gunner_move_stand;     
                   1049:        self->monsterinfo.scale = MODEL_SCALE;
                   1050: 
                   1051:        // PMM
                   1052:        self->monsterinfo.blindfire = true;
                   1053: 
                   1054:        walkmonster_start (self);
                   1055: }

unix.superglobalmegacorp.com

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