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