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