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

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

unix.superglobalmegacorp.com

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