Annotation of quake2/game/m_medic.c, revision 1.1

1.1     ! root        1: /*
        !             2: ==============================================================================
        !             3: 
        !             4: MEDIC
        !             5: 
        !             6: ==============================================================================
        !             7: */
        !             8: 
        !             9: #include "g_local.h"
        !            10: #include "m_medic.h"
        !            11: 
        !            12: qboolean visible (edict_t *self, edict_t *other);
        !            13: 
        !            14: 
        !            15: static int     sound_idle1;
        !            16: static int     sound_pain1;
        !            17: static int     sound_pain2;
        !            18: static int     sound_die;
        !            19: static int     sound_sight;
        !            20: static int     sound_search;
        !            21: static int     sound_hook_launch;
        !            22: static int     sound_hook_hit;
        !            23: static int     sound_hook_heal;
        !            24: static int     sound_hook_retract;
        !            25: 
        !            26: 
        !            27: edict_t *medic_FindDeadMonster (edict_t *self)
        !            28: {
        !            29:        edict_t *ent = NULL;
        !            30:        edict_t *best = NULL;
        !            31: 
        !            32:        while ((ent = findradius(ent, self->s.origin, 1024)) != NULL)
        !            33:        {
        !            34:                if (ent == self)
        !            35:                        continue;
        !            36:                if (!(ent->svflags & SVF_MONSTER))
        !            37:                        continue;
        !            38:                if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
        !            39:                        continue;
        !            40:                if (ent->owner)
        !            41:                        continue;
        !            42:                if (ent->health > 0)
        !            43:                        continue;
        !            44:                if (ent->nextthink)
        !            45:                        continue;
        !            46:                if (!visible(self, ent))
        !            47:                        continue;
        !            48:                if (!best)
        !            49:                {
        !            50:                        best = ent;
        !            51:                        continue;
        !            52:                }
        !            53:                if (ent->max_health <= best->max_health)
        !            54:                        continue;
        !            55:                best = ent;
        !            56:        }
        !            57: 
        !            58:        return best;
        !            59: }
        !            60: 
        !            61: void medic_idle (edict_t *self)
        !            62: {
        !            63:        edict_t *ent;
        !            64: 
        !            65:        gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
        !            66: 
        !            67:        ent = medic_FindDeadMonster(self);
        !            68:        if (ent)
        !            69:        {
        !            70:                self->enemy = ent;
        !            71:                self->enemy->owner = self;
        !            72:                self->monsterinfo.aiflags |= AI_MEDIC;
        !            73:                FoundTarget (self);
        !            74:        }
        !            75: }
        !            76: 
        !            77: void medic_search (edict_t *self)
        !            78: {
        !            79:        edict_t *ent;
        !            80: 
        !            81:        gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);
        !            82: 
        !            83:        if (!self->oldenemy)
        !            84:        {
        !            85:                ent = medic_FindDeadMonster(self);
        !            86:                if (ent)
        !            87:                {
        !            88:                        self->oldenemy = self->enemy;
        !            89:                        self->enemy = ent;
        !            90:                        self->enemy->owner = self;
        !            91:                        self->monsterinfo.aiflags |= AI_MEDIC;
        !            92:                        FoundTarget (self);
        !            93:                }
        !            94:        }
        !            95: }
        !            96: 
        !            97: void medic_sight (edict_t *self, edict_t *other)
        !            98: {
        !            99:        gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
        !           100: }
        !           101: 
        !           102: 
        !           103: mframe_t medic_frames_stand [] =
        !           104: {
        !           105:        ai_stand, 0, medic_idle,
        !           106:        ai_stand, 0, NULL,
        !           107:        ai_stand, 0, NULL,
        !           108:        ai_stand, 0, NULL,
        !           109:        ai_stand, 0, NULL,
        !           110:        ai_stand, 0, NULL,
        !           111:        ai_stand, 0, NULL,
        !           112:        ai_stand, 0, NULL,
        !           113:        ai_stand, 0, NULL,
        !           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, NULL,
        !           124:        ai_stand, 0, NULL,
        !           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, NULL,
        !           135:        ai_stand, 0, NULL,
        !           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, NULL,
        !           146:        ai_stand, 0, NULL,
        !           147:        ai_stand, 0, NULL,
        !           148:        ai_stand, 0, NULL,
        !           149:        ai_stand, 0, NULL,
        !           150:        ai_stand, 0, NULL,
        !           151:        ai_stand, 0, NULL,
        !           152:        ai_stand, 0, NULL,
        !           153:        ai_stand, 0, NULL,
        !           154:        ai_stand, 0, NULL,
        !           155:        ai_stand, 0, NULL,
        !           156:        ai_stand, 0, NULL,
        !           157:        ai_stand, 0, NULL,
        !           158:        ai_stand, 0, NULL,
        !           159:        ai_stand, 0, NULL,
        !           160:        ai_stand, 0, NULL,
        !           161:        ai_stand, 0, NULL,
        !           162:        ai_stand, 0, NULL,
        !           163:        ai_stand, 0, NULL,
        !           164:        ai_stand, 0, NULL,
        !           165:        ai_stand, 0, NULL,
        !           166:        ai_stand, 0, NULL,
        !           167:        ai_stand, 0, NULL,
        !           168:        ai_stand, 0, NULL,
        !           169:        ai_stand, 0, NULL,
        !           170:        ai_stand, 0, NULL,
        !           171:        ai_stand, 0, NULL,
        !           172:        ai_stand, 0, NULL,
        !           173:        ai_stand, 0, NULL,
        !           174:        ai_stand, 0, NULL,
        !           175:        ai_stand, 0, NULL,
        !           176:        ai_stand, 0, NULL,
        !           177:        ai_stand, 0, NULL,
        !           178:        ai_stand, 0, NULL,
        !           179:        ai_stand, 0, NULL,
        !           180:        ai_stand, 0, NULL,
        !           181:        ai_stand, 0, NULL,
        !           182:        ai_stand, 0, NULL,
        !           183:        ai_stand, 0, NULL,
        !           184:        ai_stand, 0, NULL,
        !           185:        ai_stand, 0, NULL,
        !           186:        ai_stand, 0, NULL,
        !           187:        ai_stand, 0, NULL,
        !           188:        ai_stand, 0, NULL,
        !           189:        ai_stand, 0, NULL,
        !           190:        ai_stand, 0, NULL,
        !           191:        ai_stand, 0, NULL,
        !           192:        ai_stand, 0, NULL,
        !           193:        ai_stand, 0, NULL,
        !           194:        ai_stand, 0, NULL,
        !           195: 
        !           196: };
        !           197: mmove_t medic_move_stand = {FRAME_wait1, FRAME_wait90, medic_frames_stand, NULL};
        !           198: 
        !           199: void medic_stand (edict_t *self)
        !           200: {
        !           201:        self->monsterinfo.currentmove = &medic_move_stand;
        !           202: }
        !           203: 
        !           204: 
        !           205: mframe_t medic_frames_walk [] =
        !           206: {
        !           207:        ai_walk, 6.2,   NULL,
        !           208:        ai_walk, 18.1,  NULL,
        !           209:        ai_walk, 1,             NULL,
        !           210:        ai_walk, 9,             NULL,
        !           211:        ai_walk, 10,    NULL,
        !           212:        ai_walk, 9,             NULL,
        !           213:        ai_walk, 11,    NULL,
        !           214:        ai_walk, 11.6,  NULL,
        !           215:        ai_walk, 2,             NULL,
        !           216:        ai_walk, 9.9,   NULL,
        !           217:        ai_walk, 14,    NULL,
        !           218:        ai_walk, 9.3,   NULL
        !           219: };
        !           220: mmove_t medic_move_walk = {FRAME_walk1, FRAME_walk12, medic_frames_walk, NULL};
        !           221: 
        !           222: void medic_walk (edict_t *self)
        !           223: {
        !           224:        self->monsterinfo.currentmove = &medic_move_walk;
        !           225: }
        !           226: 
        !           227: 
        !           228: mframe_t medic_frames_run [] =
        !           229: {
        !           230:        ai_run, 18,             NULL,
        !           231:        ai_run, 22.5,   NULL,
        !           232:        ai_run, 25.4,   NULL,
        !           233:        ai_run, 23.4,   NULL,
        !           234:        ai_run, 24,             NULL,
        !           235:        ai_run, 35.6,   NULL
        !           236:        
        !           237: };
        !           238: mmove_t medic_move_run = {FRAME_run1, FRAME_run6, medic_frames_run, NULL};
        !           239: 
        !           240: void medic_run (edict_t *self)
        !           241: {
        !           242:        if (!(self->monsterinfo.aiflags & AI_MEDIC))
        !           243:        {
        !           244:                edict_t *ent;
        !           245: 
        !           246:                ent = medic_FindDeadMonster(self);
        !           247:                if (ent)
        !           248:                {
        !           249:                        self->oldenemy = self->enemy;
        !           250:                        self->enemy = ent;
        !           251:                        self->enemy->owner = self;
        !           252:                        self->monsterinfo.aiflags |= AI_MEDIC;
        !           253:                        FoundTarget (self);
        !           254:                        return;
        !           255:                }
        !           256:        }
        !           257: 
        !           258:        if (self->monsterinfo.aiflags & AI_STAND_GROUND)
        !           259:                self->monsterinfo.currentmove = &medic_move_stand;
        !           260:        else
        !           261:                self->monsterinfo.currentmove = &medic_move_run;
        !           262: }
        !           263: 
        !           264: 
        !           265: mframe_t medic_frames_pain1 [] =
        !           266: {
        !           267:        ai_move, 0, NULL,
        !           268:        ai_move, 0, NULL,
        !           269:        ai_move, 0, NULL,
        !           270:        ai_move, 0, NULL,
        !           271:        ai_move, 0, NULL,
        !           272:        ai_move, 0, NULL,
        !           273:        ai_move, 0, NULL,
        !           274:        ai_move, 0, NULL
        !           275: };
        !           276: mmove_t medic_move_pain1 = {FRAME_paina1, FRAME_paina8, medic_frames_pain1, medic_run};
        !           277: 
        !           278: mframe_t medic_frames_pain2 [] =
        !           279: {
        !           280:        ai_move, 0, NULL,
        !           281:        ai_move, 0, NULL,
        !           282:        ai_move, 0, NULL,
        !           283:        ai_move, 0, NULL,
        !           284:        ai_move, 0, NULL,
        !           285:        ai_move, 0, NULL,
        !           286:        ai_move, 0, NULL,
        !           287:        ai_move, 0, NULL,
        !           288:        ai_move, 0, NULL,
        !           289:        ai_move, 0, NULL,
        !           290:        ai_move, 0, NULL,
        !           291:        ai_move, 0, NULL,
        !           292:        ai_move, 0, NULL,
        !           293:        ai_move, 0, NULL,
        !           294:        ai_move, 0, NULL
        !           295: };
        !           296: mmove_t medic_move_pain2 = {FRAME_painb1, FRAME_painb15, medic_frames_pain2, medic_run};
        !           297: 
        !           298: void medic_pain (edict_t *self, edict_t *other, float kick, int damage)
        !           299: {
        !           300:        if (self->health < (self->max_health / 2))
        !           301:                self->s.skinnum = 1;
        !           302: 
        !           303:        if (level.time < self->pain_debounce_time)
        !           304:                return;
        !           305: 
        !           306:        self->pain_debounce_time = level.time + 3;
        !           307: 
        !           308:        if (skill->value == 3)
        !           309:                return;         // no pain anims in nightmare
        !           310: 
        !           311:        if (random() < 0.5)
        !           312:        {
        !           313:                self->monsterinfo.currentmove = &medic_move_pain1;
        !           314:                gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
        !           315:        }
        !           316:        else
        !           317:        {
        !           318:                self->monsterinfo.currentmove = &medic_move_pain2;
        !           319:                gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
        !           320:        }
        !           321: }
        !           322: 
        !           323: void medic_fire_blaster (edict_t *self)
        !           324: {
        !           325:        vec3_t  start;
        !           326:        vec3_t  forward, right;
        !           327:        vec3_t  end;
        !           328:        vec3_t  dir;
        !           329:        int             effect;
        !           330: 
        !           331:        if ((self->s.frame == FRAME_attack9) || (self->s.frame == FRAME_attack12))
        !           332:                effect = EF_BLASTER;
        !           333:        else if ((self->s.frame == FRAME_attack19) || (self->s.frame == FRAME_attack22) || (self->s.frame == FRAME_attack25) || (self->s.frame == FRAME_attack28))
        !           334:                effect = EF_HYPERBLASTER;
        !           335:        else
        !           336:                effect = 0;
        !           337: 
        !           338:        AngleVectors (self->s.angles, forward, right, NULL);
        !           339:        G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MEDIC_BLASTER_1], forward, right, start);
        !           340: 
        !           341:        VectorCopy (self->enemy->s.origin, end);
        !           342:        end[2] += self->enemy->viewheight;
        !           343:        VectorSubtract (end, start, dir);
        !           344: 
        !           345:        monster_fire_blaster (self, start, dir, 2, 1000, MZ2_MEDIC_BLASTER_1, effect);
        !           346: }
        !           347: 
        !           348: 
        !           349: void medic_dead (edict_t *self)
        !           350: {
        !           351:        VectorSet (self->mins, -16, -16, -24);
        !           352:        VectorSet (self->maxs, 16, 16, -8);
        !           353:        self->movetype = MOVETYPE_TOSS;
        !           354:        self->svflags |= SVF_DEADMONSTER;
        !           355:        self->nextthink = 0;
        !           356:        gi.linkentity (self);
        !           357: }
        !           358: 
        !           359: mframe_t medic_frames_death [] =
        !           360: {
        !           361:        ai_move, 0, NULL,
        !           362:        ai_move, 0, NULL,
        !           363:        ai_move, 0, NULL,
        !           364:        ai_move, 0, NULL,
        !           365:        ai_move, 0, NULL,
        !           366:        ai_move, 0, NULL,
        !           367:        ai_move, 0, NULL,
        !           368:        ai_move, 0, NULL,
        !           369:        ai_move, 0, NULL,
        !           370:        ai_move, 0, NULL,
        !           371:        ai_move, 0, NULL,
        !           372:        ai_move, 0, NULL,
        !           373:        ai_move, 0, NULL,
        !           374:        ai_move, 0, NULL,
        !           375:        ai_move, 0, NULL,
        !           376:        ai_move, 0, NULL,
        !           377:        ai_move, 0, NULL,
        !           378:        ai_move, 0, NULL,
        !           379:        ai_move, 0, NULL,
        !           380:        ai_move, 0, NULL,
        !           381:        ai_move, 0, NULL,
        !           382:        ai_move, 0, NULL,
        !           383:        ai_move, 0, NULL,
        !           384:        ai_move, 0, NULL,
        !           385:        ai_move, 0, NULL,
        !           386:        ai_move, 0, NULL,
        !           387:        ai_move, 0, NULL,
        !           388:        ai_move, 0, NULL,
        !           389:        ai_move, 0, NULL,
        !           390:        ai_move, 0, NULL
        !           391: };
        !           392: mmove_t medic_move_death = {FRAME_death1, FRAME_death30, medic_frames_death, medic_dead};
        !           393: 
        !           394: void medic_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
        !           395: {
        !           396:        int             n;
        !           397: 
        !           398:        // if we had a pending patient, free him up for another medic
        !           399:        if ((self->enemy) && (self->enemy->owner == self))
        !           400:                self->enemy->owner = NULL;
        !           401: 
        !           402: // check for gib
        !           403:        if (self->health <= self->gib_health)
        !           404:        {
        !           405:                gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
        !           406:                for (n= 0; n < 2; n++)
        !           407:                        ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
        !           408:                for (n= 0; n < 4; n++)
        !           409:                        ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
        !           410:                ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
        !           411:                self->deadflag = DEAD_DEAD;
        !           412:                return;
        !           413:        }
        !           414: 
        !           415:        if (self->deadflag == DEAD_DEAD)
        !           416:                return;
        !           417: 
        !           418: // regular death
        !           419:        gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
        !           420:        self->deadflag = DEAD_DEAD;
        !           421:        self->takedamage = DAMAGE_YES;
        !           422: 
        !           423:        self->monsterinfo.currentmove = &medic_move_death;
        !           424: }
        !           425: 
        !           426: 
        !           427: void medic_duck_down (edict_t *self)
        !           428: {
        !           429:        if (self->monsterinfo.aiflags & AI_DUCKED)
        !           430:                return;
        !           431:        self->monsterinfo.aiflags |= AI_DUCKED;
        !           432:        self->maxs[2] -= 32;
        !           433:        self->takedamage = DAMAGE_YES;
        !           434:        self->monsterinfo.pausetime = level.time + 1;
        !           435:        gi.linkentity (self);
        !           436: }
        !           437: 
        !           438: void medic_duck_hold (edict_t *self)
        !           439: {
        !           440:        if (level.time >= self->monsterinfo.pausetime)
        !           441:                self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
        !           442:        else
        !           443:                self->monsterinfo.aiflags |= AI_HOLD_FRAME;
        !           444: }
        !           445: 
        !           446: void medic_duck_up (edict_t *self)
        !           447: {
        !           448:        self->monsterinfo.aiflags &= ~AI_DUCKED;
        !           449:        self->maxs[2] += 32;
        !           450:        self->takedamage = DAMAGE_AIM;
        !           451:        gi.linkentity (self);
        !           452: }
        !           453: 
        !           454: mframe_t medic_frames_duck [] =
        !           455: {
        !           456:        ai_move, -1,    NULL,
        !           457:        ai_move, -1,    NULL,
        !           458:        ai_move, -1,    medic_duck_down,
        !           459:        ai_move, -1,    medic_duck_hold,
        !           460:        ai_move, -1,    NULL,
        !           461:        ai_move, -1,    NULL,
        !           462:        ai_move, -1,    medic_duck_up,
        !           463:        ai_move, -1,    NULL,
        !           464:        ai_move, -1,    NULL,
        !           465:        ai_move, -1,    NULL,
        !           466:        ai_move, -1,    NULL,
        !           467:        ai_move, -1,    NULL,
        !           468:        ai_move, -1,    NULL,
        !           469:        ai_move, -1,    NULL,
        !           470:        ai_move, -1,    NULL,
        !           471:        ai_move, -1,    NULL
        !           472: };
        !           473: mmove_t medic_move_duck = {FRAME_duck1, FRAME_duck16, medic_frames_duck, medic_run};
        !           474: 
        !           475: void medic_dodge (edict_t *self, edict_t *attacker, float eta)
        !           476: {
        !           477:        if (random() > 0.25)
        !           478:                return;
        !           479: 
        !           480:        if (!self->enemy)
        !           481:                self->enemy = attacker;
        !           482: 
        !           483:        self->monsterinfo.currentmove = &medic_move_duck;
        !           484: }
        !           485: 
        !           486: mframe_t medic_frames_attackHyperBlaster [] =
        !           487: {
        !           488:        ai_charge, 0,   NULL,
        !           489:        ai_charge, 0,   NULL,
        !           490:        ai_charge, 0,   NULL,
        !           491:        ai_charge, 0,   NULL,
        !           492:        ai_charge, 0,   medic_fire_blaster,
        !           493:        ai_charge, 0,   medic_fire_blaster,
        !           494:        ai_charge, 0,   medic_fire_blaster,
        !           495:        ai_charge, 0,   medic_fire_blaster,
        !           496:        ai_charge, 0,   medic_fire_blaster,
        !           497:        ai_charge, 0,   medic_fire_blaster,
        !           498:        ai_charge, 0,   medic_fire_blaster,
        !           499:        ai_charge, 0,   medic_fire_blaster,
        !           500:        ai_charge, 0,   medic_fire_blaster,
        !           501:        ai_charge, 0,   medic_fire_blaster,
        !           502:        ai_charge, 0,   medic_fire_blaster,
        !           503:        ai_charge, 0,   medic_fire_blaster
        !           504: };
        !           505: mmove_t medic_move_attackHyperBlaster = {FRAME_attack15, FRAME_attack30, medic_frames_attackHyperBlaster, medic_run};
        !           506: 
        !           507: 
        !           508: void medic_continue (edict_t *self)
        !           509: {
        !           510:        if (visible (self, self->enemy) )
        !           511:                if (random() <= 0.95)
        !           512:                        self->monsterinfo.currentmove = &medic_move_attackHyperBlaster;
        !           513: }
        !           514: 
        !           515: 
        !           516: mframe_t medic_frames_attackBlaster [] =
        !           517: {
        !           518:        ai_charge, 0,   NULL,
        !           519:        ai_charge, 5,   NULL,
        !           520:        ai_charge, 5,   NULL,
        !           521:        ai_charge, 3,   NULL,
        !           522:        ai_charge, 2,   NULL,
        !           523:        ai_charge, 0,   NULL,
        !           524:        ai_charge, 0,   NULL,
        !           525:        ai_charge, 0,   NULL,
        !           526:        ai_charge, 0,   medic_fire_blaster,
        !           527:        ai_charge, 0,   NULL,
        !           528:        ai_charge, 0,   NULL,
        !           529:        ai_charge, 0,   medic_fire_blaster,     
        !           530:        ai_charge, 0,   NULL,
        !           531:        ai_charge, 0,   medic_continue  // Change to medic_continue... Else, go to frame 32
        !           532: };
        !           533: mmove_t medic_move_attackBlaster = {FRAME_attack1, FRAME_attack14, medic_frames_attackBlaster, medic_run};
        !           534: 
        !           535: 
        !           536: void medic_hook_launch (edict_t *self)
        !           537: {
        !           538:        gi.sound (self, CHAN_WEAPON, sound_hook_launch, 1, ATTN_NORM, 0);
        !           539: }
        !           540: 
        !           541: void ED_CallSpawn (edict_t *ent);
        !           542: 
        !           543: static vec3_t  medic_cable_offsets[] =
        !           544: {
        !           545:        45.0,  -9.2, 15.5,
        !           546:        48.4,  -9.7, 15.2,
        !           547:        47.8,  -9.8, 15.8,
        !           548:        47.3,  -9.3, 14.3,
        !           549:        45.4, -10.1, 13.1,
        !           550:        41.9, -12.7, 12.0,
        !           551:        37.8, -15.8, 11.2,
        !           552:        34.3, -18.4, 10.7,
        !           553:        32.7, -19.7, 10.4,
        !           554:        32.7, -19.7, 10.4
        !           555: };
        !           556: 
        !           557: void medic_cable_attack (edict_t *self)
        !           558: {
        !           559:        vec3_t  offset, start, end, f, r;
        !           560:        trace_t tr;
        !           561:        vec3_t  dir, angles;
        !           562:        float   distance;
        !           563: 
        !           564:        if (!self->enemy->inuse)
        !           565:                return;
        !           566: 
        !           567:        AngleVectors (self->s.angles, f, r, NULL);
        !           568:        VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
        !           569:        G_ProjectSource (self->s.origin, offset, f, r, start);
        !           570: 
        !           571:        // check for max distance
        !           572:        VectorSubtract (start, self->enemy->s.origin, dir);
        !           573:        distance = VectorLength(dir);
        !           574:        if (distance > 256)
        !           575:                return;
        !           576: 
        !           577:        // check for min/max pitch
        !           578:        vectoangles (dir, angles);
        !           579:        if (angles[0] < -180)
        !           580:                angles[0] += 360;
        !           581:        if (fabs(angles[0]) > 45)
        !           582:                return;
        !           583: 
        !           584:        tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT);
        !           585:        if (tr.fraction != 1.0 && tr.ent != self->enemy)
        !           586:                return;
        !           587: 
        !           588:        if (self->s.frame == FRAME_attack43)
        !           589:        {
        !           590:                gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
        !           591:                self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
        !           592:        }
        !           593:        else if (self->s.frame == FRAME_attack50)
        !           594:        {
        !           595:                self->enemy->spawnflags = 0;
        !           596:                self->enemy->monsterinfo.aiflags = 0;
        !           597:                self->enemy->target = NULL;
        !           598:                self->enemy->targetname = NULL;
        !           599:                self->enemy->combattarget = NULL;
        !           600:                self->enemy->deathtarget = NULL;
        !           601:                self->enemy->owner = self;
        !           602:                ED_CallSpawn (self->enemy);
        !           603:                self->enemy->owner = NULL;
        !           604:                if (self->enemy->think)
        !           605:                {
        !           606:                        self->enemy->nextthink = level.time;
        !           607:                        self->enemy->think (self->enemy);
        !           608:                }
        !           609:                self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
        !           610:                if (self->oldenemy && self->oldenemy->client)
        !           611:                {
        !           612:                        self->enemy->enemy = self->oldenemy;
        !           613:                        FoundTarget (self->enemy);
        !           614:                }
        !           615:        }
        !           616:        else
        !           617:        {
        !           618:                if (self->s.frame == FRAME_attack44)
        !           619:                        gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
        !           620:        }
        !           621: 
        !           622:        // adjust start for beam origin being in middle of a segment
        !           623:        VectorMA (start, 8, f, start);
        !           624: 
        !           625:        // adjust end z for end spot since the monster is currently dead
        !           626:        VectorCopy (self->enemy->s.origin, end);
        !           627:        end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;
        !           628: 
        !           629:        gi.WriteByte (svc_temp_entity);
        !           630:        gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
        !           631:        gi.WriteShort (self - g_edicts);
        !           632:        gi.WritePosition (start);
        !           633:        gi.WritePosition (end);
        !           634:        gi.multicast (self->s.origin, MULTICAST_PVS);
        !           635: }
        !           636: 
        !           637: void medic_hook_retract (edict_t *self)
        !           638: {
        !           639:        gi.sound (self, CHAN_WEAPON, sound_hook_retract, 1, ATTN_NORM, 0);
        !           640:        self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
        !           641: }
        !           642: 
        !           643: mframe_t medic_frames_attackCable [] =
        !           644: {
        !           645:        ai_move, 2,             NULL,
        !           646:        ai_move, 3,             NULL,
        !           647:        ai_move, 5,             NULL,
        !           648:        ai_move, 4.4,   NULL,
        !           649:        ai_charge, 4.7, NULL,
        !           650:        ai_charge, 5,   NULL,
        !           651:        ai_charge, 6,   NULL,
        !           652:        ai_charge, 4,   NULL,
        !           653:        ai_charge, 0,   NULL,
        !           654:        ai_move, 0,             medic_hook_launch,
        !           655:        ai_move, 0,             medic_cable_attack,
        !           656:        ai_move, 0,             medic_cable_attack,
        !           657:        ai_move, 0,             medic_cable_attack,
        !           658:        ai_move, 0,             medic_cable_attack,
        !           659:        ai_move, 0,             medic_cable_attack,
        !           660:        ai_move, 0,             medic_cable_attack,
        !           661:        ai_move, 0,             medic_cable_attack,
        !           662:        ai_move, 0,             medic_cable_attack,
        !           663:        ai_move, 0,             medic_cable_attack,
        !           664:        ai_move, -15,   medic_hook_retract,
        !           665:        ai_move, -1.5,  NULL,
        !           666:        ai_move, -1.2,  NULL,
        !           667:        ai_move, -3,    NULL,
        !           668:        ai_move, -2,    NULL,
        !           669:        ai_move, 0.3,   NULL,
        !           670:        ai_move, 0.7,   NULL,
        !           671:        ai_move, 1.2,   NULL,
        !           672:        ai_move, 1.3,   NULL
        !           673: };
        !           674: mmove_t medic_move_attackCable = {FRAME_attack33, FRAME_attack60, medic_frames_attackCable, medic_run};
        !           675: 
        !           676: 
        !           677: void medic_attack(edict_t *self)
        !           678: {
        !           679:        if (self->monsterinfo.aiflags & AI_MEDIC)
        !           680:                self->monsterinfo.currentmove = &medic_move_attackCable;
        !           681:        else
        !           682:                self->monsterinfo.currentmove = &medic_move_attackBlaster;
        !           683: }
        !           684: 
        !           685: qboolean medic_checkattack (edict_t *self)
        !           686: {
        !           687:        if (self->monsterinfo.aiflags & AI_MEDIC)
        !           688:        {
        !           689:                medic_attack(self);
        !           690:                return true;
        !           691:        }
        !           692: 
        !           693:        return M_CheckAttack (self);
        !           694: }
        !           695: 
        !           696: 
        !           697: /*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
        !           698: */
        !           699: void SP_monster_medic (edict_t *self)
        !           700: {
        !           701:        if (deathmatch->value)
        !           702:        {
        !           703:                G_FreeEdict (self);
        !           704:                return;
        !           705:        }
        !           706: 
        !           707:        sound_idle1 = gi.soundindex ("medic/idle.wav");
        !           708:        sound_pain1 = gi.soundindex ("medic/medpain1.wav");
        !           709:        sound_pain2 = gi.soundindex ("medic/medpain2.wav");
        !           710:        sound_die = gi.soundindex ("medic/meddeth1.wav");
        !           711:        sound_sight = gi.soundindex ("medic/medsght1.wav");
        !           712:        sound_search = gi.soundindex ("medic/medsrch1.wav");
        !           713:        sound_hook_launch = gi.soundindex ("medic/medatck2.wav");
        !           714:        sound_hook_hit = gi.soundindex ("medic/medatck3.wav");
        !           715:        sound_hook_heal = gi.soundindex ("medic/medatck4.wav");
        !           716:        sound_hook_retract = gi.soundindex ("medic/medatck5.wav");
        !           717: 
        !           718:        gi.soundindex ("medic/medatck1.wav");
        !           719: 
        !           720:        self->movetype = MOVETYPE_STEP;
        !           721:        self->solid = SOLID_BBOX;
        !           722:        self->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2");
        !           723:        VectorSet (self->mins, -24, -24, -24);
        !           724:        VectorSet (self->maxs, 24, 24, 32);
        !           725: 
        !           726:        self->health = 300;
        !           727:        self->gib_health = -130;
        !           728:        self->mass = 400;
        !           729: 
        !           730:        self->pain = medic_pain;
        !           731:        self->die = medic_die;
        !           732: 
        !           733:        self->monsterinfo.stand = medic_stand;
        !           734:        self->monsterinfo.walk = medic_walk;
        !           735:        self->monsterinfo.run = medic_run;
        !           736:        self->monsterinfo.dodge = medic_dodge;
        !           737:        self->monsterinfo.attack = medic_attack;
        !           738:        self->monsterinfo.melee = NULL;
        !           739:        self->monsterinfo.sight = medic_sight;
        !           740:        self->monsterinfo.idle = medic_idle;
        !           741:        self->monsterinfo.search = medic_search;
        !           742:        self->monsterinfo.checkattack = medic_checkattack;
        !           743: 
        !           744:        gi.linkentity (self);
        !           745: 
        !           746:        self->monsterinfo.currentmove = &medic_move_stand;
        !           747:        self->monsterinfo.scale = MODEL_SCALE;
        !           748: 
        !           749:        walkmonster_start (self);
        !           750: }

unix.superglobalmegacorp.com

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