Annotation of quake2/ctf/g_monster.c, revision 1.1.1.2

1.1.1.2 ! root        1: /*
        !             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: */
1.1       root       20: #include "g_local.h"
                     21: 
                     22: 
                     23: //
                     24: // monster weapons
                     25: //
                     26: 
                     27: //FIXME mosnters should call these with a totally accurate direction
                     28: // and we can mess it up based on skill.  Spread should be for normal
                     29: // and we can tighten or loosen based on skill.  We could muck with
                     30: // the damages too, but I'm not sure that's such a good idea.
                     31: void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype)
                     32: {
                     33:        fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN);
                     34: 
                     35:        gi.WriteByte (svc_muzzleflash2);
                     36:        gi.WriteShort (self - g_edicts);
                     37:        gi.WriteByte (flashtype);
                     38:        gi.multicast (start, MULTICAST_PVS);
                     39: }
                     40: 
                     41: void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype)
                     42: {
                     43:        fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);
                     44: 
                     45:        gi.WriteByte (svc_muzzleflash2);
                     46:        gi.WriteShort (self - g_edicts);
                     47:        gi.WriteByte (flashtype);
                     48:        gi.multicast (start, MULTICAST_PVS);
                     49: }
                     50: 
                     51: void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
                     52: {
                     53:        fire_blaster (self, start, dir, damage, speed, effect, false);
                     54: 
                     55:        gi.WriteByte (svc_muzzleflash2);
                     56:        gi.WriteShort (self - g_edicts);
                     57:        gi.WriteByte (flashtype);
                     58:        gi.multicast (start, MULTICAST_PVS);
                     59: }      
                     60: 
                     61: void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype)
                     62: {
                     63:        fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40);
                     64: 
                     65:        gi.WriteByte (svc_muzzleflash2);
                     66:        gi.WriteShort (self - g_edicts);
                     67:        gi.WriteByte (flashtype);
                     68:        gi.multicast (start, MULTICAST_PVS);
                     69: }
                     70: 
                     71: void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
                     72: {
                     73:        fire_rocket (self, start, dir, damage, speed, damage+20, damage);
                     74: 
                     75:        gi.WriteByte (svc_muzzleflash2);
                     76:        gi.WriteShort (self - g_edicts);
                     77:        gi.WriteByte (flashtype);
                     78:        gi.multicast (start, MULTICAST_PVS);
                     79: }      
                     80: 
                     81: void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype)
                     82: {
                     83:        fire_rail (self, start, aimdir, damage, kick);
                     84: 
                     85:        gi.WriteByte (svc_muzzleflash2);
                     86:        gi.WriteShort (self - g_edicts);
                     87:        gi.WriteByte (flashtype);
                     88:        gi.multicast (start, MULTICAST_PVS);
                     89: }
                     90: 
                     91: void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype)
                     92: {
                     93:        fire_bfg (self, start, aimdir, damage, speed, damage_radius);
                     94: 
                     95:        gi.WriteByte (svc_muzzleflash2);
                     96:        gi.WriteShort (self - g_edicts);
                     97:        gi.WriteByte (flashtype);
                     98:        gi.multicast (start, MULTICAST_PVS);
                     99: }
                    100: 
                    101: 
                    102: 
                    103: //
                    104: // Monster utility functions
                    105: //
                    106: 
                    107: static void M_FliesOff (edict_t *self)
                    108: {
                    109:        self->s.effects &= ~EF_FLIES;
                    110:        self->s.sound = 0;
                    111: }
                    112: 
                    113: static void M_FliesOn (edict_t *self)
                    114: {
                    115:        if (self->waterlevel)
                    116:                return;
                    117:        self->s.effects |= EF_FLIES;
                    118:        self->s.sound = gi.soundindex ("infantry/inflies1.wav");
                    119:        self->think = M_FliesOff;
                    120:        self->nextthink = level.time + 60;
                    121: }
                    122: 
                    123: void M_FlyCheck (edict_t *self)
                    124: {
                    125:        if (self->waterlevel)
                    126:                return;
                    127: 
                    128:        if (random() > 0.5)
                    129:                return;
                    130: 
                    131:        self->think = M_FliesOn;
                    132:        self->nextthink = level.time + 5 + 10 * random();
                    133: }
                    134: 
                    135: void AttackFinished (edict_t *self, float time)
                    136: {
                    137:        self->monsterinfo.attack_finished = level.time + time;
                    138: }
                    139: 
                    140: 
                    141: void M_CheckGround (edict_t *ent)
                    142: {
                    143:        vec3_t          point;
                    144:        trace_t         trace;
                    145: 
                    146:        if (ent->flags & (FL_SWIM|FL_FLY))
                    147:                return;
                    148: 
                    149:        if (ent->velocity[2] > 100)
                    150:        {
                    151:                ent->groundentity = NULL;
                    152:                return;
                    153:        }
                    154: 
                    155: // if the hull point one-quarter unit down is solid the entity is on ground
                    156:        point[0] = ent->s.origin[0];
                    157:        point[1] = ent->s.origin[1];
                    158:        point[2] = ent->s.origin[2] - 0.25;
                    159: 
                    160:        trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
                    161: 
                    162:        // check steepness
                    163:        if ( trace.plane.normal[2] < 0.7 && !trace.startsolid)
                    164:        {
                    165:                ent->groundentity = NULL;
                    166:                return;
                    167:        }
                    168: 
                    169: //     ent->groundentity = trace.ent;
                    170: //     ent->groundentity_linkcount = trace.ent->linkcount;
                    171: //     if (!trace.startsolid && !trace.allsolid)
                    172: //             VectorCopy (trace.endpos, ent->s.origin);
                    173:        if (!trace.startsolid && !trace.allsolid)
                    174:        {
                    175:                VectorCopy (trace.endpos, ent->s.origin);
                    176:                ent->groundentity = trace.ent;
                    177:                ent->groundentity_linkcount = trace.ent->linkcount;
                    178:                ent->velocity[2] = 0;
                    179:        }
                    180: }
                    181: 
                    182: 
                    183: void M_CatagorizePosition (edict_t *ent)
                    184: {
                    185:        vec3_t          point;
                    186:        int                     cont;
                    187: 
                    188: //
                    189: // get waterlevel
                    190: //
                    191:        point[0] = ent->s.origin[0];
                    192:        point[1] = ent->s.origin[1];
                    193:        point[2] = ent->s.origin[2] + ent->mins[2] + 1; 
                    194:        cont = gi.pointcontents (point);
                    195: 
                    196:        if (!(cont & MASK_WATER))
                    197:        {
                    198:                ent->waterlevel = 0;
                    199:                ent->watertype = 0;
                    200:                return;
                    201:        }
                    202: 
                    203:        ent->watertype = cont;
                    204:        ent->waterlevel = 1;
                    205:        point[2] += 26;
                    206:        cont = gi.pointcontents (point);
                    207:        if (!(cont & MASK_WATER))
                    208:                return;
                    209: 
                    210:        ent->waterlevel = 2;
                    211:        point[2] += 22;
                    212:        cont = gi.pointcontents (point);
                    213:        if (cont & MASK_WATER)
                    214:                ent->waterlevel = 3;
                    215: }
                    216: 
                    217: 
                    218: void M_WorldEffects (edict_t *ent)
                    219: {
                    220:        int             dmg;
                    221: 
                    222:        if (ent->health > 0)
                    223:        {
                    224:                if (!(ent->flags & FL_SWIM))
                    225:                {
                    226:                        if (ent->waterlevel < 3)
                    227:                        {
                    228:                                ent->air_finished = level.time + 12;
                    229:                        }
                    230:                        else if (ent->air_finished < level.time)
                    231:                        {       // drown!
                    232:                                if (ent->pain_debounce_time < level.time)
                    233:                                {
                    234:                                        dmg = 2 + 2 * floor(level.time - ent->air_finished);
                    235:                                        if (dmg > 15)
                    236:                                                dmg = 15;
                    237:                                        T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
                    238:                                        ent->pain_debounce_time = level.time + 1;
                    239:                                }
                    240:                        }
                    241:                }
                    242:                else
                    243:                {
                    244:                        if (ent->waterlevel > 0)
                    245:                        {
                    246:                                ent->air_finished = level.time + 9;
                    247:                        }
                    248:                        else if (ent->air_finished < level.time)
                    249:                        {       // suffocate!
                    250:                                if (ent->pain_debounce_time < level.time)
                    251:                                {
                    252:                                        dmg = 2 + 2 * floor(level.time - ent->air_finished);
                    253:                                        if (dmg > 15)
                    254:                                                dmg = 15;
                    255:                                        T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
                    256:                                        ent->pain_debounce_time = level.time + 1;
                    257:                                }
                    258:                        }
                    259:                }
                    260:        }
                    261:        
                    262:        if (ent->waterlevel == 0)
                    263:        {
                    264:                if (ent->flags & FL_INWATER)
                    265:                {       
                    266:                        gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
                    267:                        ent->flags &= ~FL_INWATER;
                    268:                }
                    269:                return;
                    270:        }
                    271: 
                    272:        if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA))
                    273:        {
                    274:                if (ent->damage_debounce_time < level.time)
                    275:                {
                    276:                        ent->damage_debounce_time = level.time + 0.2;
                    277:                        T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA);
                    278:                }
                    279:        }
                    280:        if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME))
                    281:        {
                    282:                if (ent->damage_debounce_time < level.time)
                    283:                {
                    284:                        ent->damage_debounce_time = level.time + 1;
                    285:                        T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME);
                    286:                }
                    287:        }
                    288:        
                    289:        if ( !(ent->flags & FL_INWATER) )
                    290:        {       
                    291:                if (!(ent->svflags & SVF_DEADMONSTER))
                    292:                {
                    293:                        if (ent->watertype & CONTENTS_LAVA)
                    294:                                if (random() <= 0.5)
                    295:                                        gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0);
                    296:                                else
                    297:                                        gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0);
                    298:                        else if (ent->watertype & CONTENTS_SLIME)
                    299:                                gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
                    300:                        else if (ent->watertype & CONTENTS_WATER)
                    301:                                gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
                    302:                }
                    303: 
                    304:                ent->flags |= FL_INWATER;
                    305:                ent->damage_debounce_time = 0;
                    306:        }
                    307: }
                    308: 
                    309: 
                    310: void M_droptofloor (edict_t *ent)
                    311: {
                    312:        vec3_t          end;
                    313:        trace_t         trace;
                    314: 
                    315:        ent->s.origin[2] += 1;
                    316:        VectorCopy (ent->s.origin, end);
                    317:        end[2] -= 256;
                    318:        
                    319:        trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
                    320: 
                    321:        if (trace.fraction == 1 || trace.allsolid)
                    322:                return;
                    323: 
                    324:        VectorCopy (trace.endpos, ent->s.origin);
                    325: 
                    326:        gi.linkentity (ent);
                    327:        M_CheckGround (ent);
                    328:        M_CatagorizePosition (ent);
                    329: }
                    330: 
                    331: 
                    332: void M_SetEffects (edict_t *ent)
                    333: {
                    334:        ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN);
                    335:        ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
                    336: 
                    337:        if (ent->monsterinfo.aiflags & AI_RESURRECTING)
                    338:        {
                    339:                ent->s.effects |= EF_COLOR_SHELL;
                    340:                ent->s.renderfx |= RF_SHELL_RED;
                    341:        }
                    342: 
                    343:        if (ent->health <= 0)
                    344:                return;
                    345: 
                    346:        if (ent->powerarmor_time > level.time)
                    347:        {
                    348:                if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN)
                    349:                {
                    350:                        ent->s.effects |= EF_POWERSCREEN;
                    351:                }
                    352:                else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD)
                    353:                {
                    354:                        ent->s.effects |= EF_COLOR_SHELL;
                    355:                        ent->s.renderfx |= RF_SHELL_GREEN;
                    356:                }
                    357:        }
                    358: }
                    359: 
                    360: 
                    361: void M_MoveFrame (edict_t *self)
                    362: {
                    363:        mmove_t *move;
                    364:        int             index;
                    365: 
                    366:        move = self->monsterinfo.currentmove;
                    367:        self->nextthink = level.time + FRAMETIME;
                    368: 
                    369:        if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe))
                    370:        {
                    371:                self->s.frame = self->monsterinfo.nextframe;
                    372:                self->monsterinfo.nextframe = 0;
                    373:        }
                    374:        else
                    375:        {
                    376:                if (self->s.frame == move->lastframe)
                    377:                {
                    378:                        if (move->endfunc)
                    379:                        {
                    380:                                move->endfunc (self);
                    381: 
                    382:                                // regrab move, endfunc is very likely to change it
                    383:                                move = self->monsterinfo.currentmove;
                    384: 
                    385:                                // check for death
                    386:                                if (self->svflags & SVF_DEADMONSTER)
                    387:                                        return;
                    388:                        }
                    389:                }
                    390: 
                    391:                if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
                    392:                {
                    393:                        self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
                    394:                        self->s.frame = move->firstframe;
                    395:                }
                    396:                else
                    397:                {
                    398:                        if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
                    399:                        {
                    400:                                self->s.frame++;
                    401:                                if (self->s.frame > move->lastframe)
                    402:                                        self->s.frame = move->firstframe;
                    403:                        }
                    404:                }
                    405:        }
                    406: 
                    407:        index = self->s.frame - move->firstframe;
                    408:        if (move->frame[index].aifunc)
                    409:                if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
                    410:                        move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
                    411:                else
                    412:                        move->frame[index].aifunc (self, 0);
                    413: 
                    414:        if (move->frame[index].thinkfunc)
                    415:                move->frame[index].thinkfunc (self);
                    416: }
                    417: 
                    418: 
                    419: void monster_think (edict_t *self)
                    420: {
                    421:        M_MoveFrame (self);
                    422:        if (self->linkcount != self->monsterinfo.linkcount)
                    423:        {
                    424:                self->monsterinfo.linkcount = self->linkcount;
                    425:                M_CheckGround (self);
                    426:        }
                    427:        M_CatagorizePosition (self);
                    428:        M_WorldEffects (self);
                    429:        M_SetEffects (self);
                    430: }
                    431: 
                    432: 
                    433: /*
                    434: ================
                    435: monster_use
                    436: 
                    437: Using a monster makes it angry at the current activator
                    438: ================
                    439: */
                    440: void monster_use (edict_t *self, edict_t *other, edict_t *activator)
                    441: {
                    442:        if (self->enemy)
                    443:                return;
                    444:        if (self->health <= 0)
                    445:                return;
                    446:        if (activator->flags & FL_NOTARGET)
                    447:                return;
                    448:        if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
                    449:                return;
                    450:        
                    451: // delay reaction so if the monster is teleported, its sound is still heard
                    452:        self->enemy = activator;
                    453:        FoundTarget (self);
                    454: }
                    455: 
                    456: 
                    457: void monster_start_go (edict_t *self);
                    458: 
                    459: 
                    460: void monster_triggered_spawn (edict_t *self)
                    461: {
                    462:        self->s.origin[2] += 1;
                    463:        KillBox (self);
                    464: 
                    465:        self->solid = SOLID_BBOX;
                    466:        self->movetype = MOVETYPE_STEP;
                    467:        self->svflags &= ~SVF_NOCLIENT;
                    468:        self->air_finished = level.time + 12;
                    469:        gi.linkentity (self);
                    470: 
                    471:        monster_start_go (self);
                    472: 
                    473:        if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
                    474:        {
                    475:                FoundTarget (self);
                    476:        }
                    477:        else
                    478:        {
                    479:                self->enemy = NULL;
                    480:        }
                    481: }
                    482: 
                    483: void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
                    484: {
                    485:        // we have a one frame delay here so we don't telefrag the guy who activated us
                    486:        self->think = monster_triggered_spawn;
                    487:        self->nextthink = level.time + FRAMETIME;
                    488:        if (activator->client)
                    489:                self->enemy = activator;
                    490:        self->use = monster_use;
                    491: }
                    492: 
                    493: void monster_triggered_start (edict_t *self)
                    494: {
                    495:        self->solid = SOLID_NOT;
                    496:        self->movetype = MOVETYPE_NONE;
                    497:        self->svflags |= SVF_NOCLIENT;
                    498:        self->nextthink = 0;
                    499:        self->use = monster_triggered_spawn_use;
                    500: }
                    501: 
                    502: 
                    503: /*
                    504: ================
                    505: monster_death_use
                    506: 
                    507: When a monster dies, it fires all of its targets with the current
                    508: enemy as activator.
                    509: ================
                    510: */
                    511: void monster_death_use (edict_t *self)
                    512: {
                    513:        self->flags &= ~(FL_FLY|FL_SWIM);
                    514:        self->monsterinfo.aiflags &= AI_GOOD_GUY;
                    515: 
                    516:        if (self->item)
                    517:        {
                    518:                Drop_Item (self, self->item);
                    519:                self->item = NULL;
                    520:        }
                    521: 
                    522:        if (self->deathtarget)
                    523:                self->target = self->deathtarget;
                    524: 
                    525:        if (!self->target)
                    526:                return;
                    527: 
                    528:        G_UseTargets (self, self->enemy);
                    529: }
                    530: 
                    531: 
                    532: //============================================================================
                    533: 
                    534: qboolean monster_start (edict_t *self)
                    535: {
                    536:        if (deathmatch->value)
                    537:        {
                    538:                G_FreeEdict (self);
                    539:                return false;
                    540:        }
                    541: 
                    542:        if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
                    543:        {
                    544:                self->spawnflags &= ~4;
                    545:                self->spawnflags |= 1;
                    546: //             gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
                    547:        }
                    548: 
                    549:        if (!(self->monsterinfo.aiflags & AI_GOOD_GUY))
                    550:                level.total_monsters++;
                    551: 
                    552:        self->nextthink = level.time + FRAMETIME;
                    553:        self->svflags |= SVF_MONSTER;
                    554:        self->s.renderfx |= RF_FRAMELERP;
                    555:        self->takedamage = DAMAGE_AIM;
                    556:        self->air_finished = level.time + 12;
                    557:        self->use = monster_use;
                    558:        self->max_health = self->health;
                    559:        self->clipmask = MASK_MONSTERSOLID;
                    560: 
                    561:        self->s.skinnum = 0;
                    562:        self->deadflag = DEAD_NO;
                    563:        self->svflags &= ~SVF_DEADMONSTER;
                    564: 
                    565:        if (!self->monsterinfo.checkattack)
                    566:                self->monsterinfo.checkattack = M_CheckAttack;
                    567:        VectorCopy (self->s.origin, self->s.old_origin);
                    568: 
                    569:        if (st.item)
                    570:        {
                    571:                self->item = FindItemByClassname (st.item);
                    572:                if (!self->item)
                    573:                        gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
                    574:        }
                    575: 
                    576:        // randomize what frame they start on
                    577:        if (self->monsterinfo.currentmove)
                    578:                self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
                    579: 
                    580:        return true;
                    581: }
                    582: 
                    583: void monster_start_go (edict_t *self)
                    584: {
                    585:        vec3_t  v;
                    586: 
                    587:        if (self->health <= 0)
                    588:                return;
                    589: 
                    590:        // check for target to combat_point and change to combattarget
                    591:        if (self->target)
                    592:        {
                    593:                qboolean        notcombat;
                    594:                qboolean        fixup;
                    595:                edict_t         *target;
                    596: 
                    597:                target = NULL;
                    598:                notcombat = false;
                    599:                fixup = false;
                    600:                while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL)
                    601:                {
                    602:                        if (strcmp(target->classname, "point_combat") == 0)
                    603:                        {
                    604:                                self->combattarget = self->target;
                    605:                                fixup = true;
                    606:                        }
                    607:                        else
                    608:                        {
                    609:                                notcombat = true;
                    610:                        }
                    611:                }
                    612:                if (notcombat && self->combattarget)
                    613:                        gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin));
                    614:                if (fixup)
                    615:                        self->target = NULL;
                    616:        }
                    617: 
                    618:        // validate combattarget
                    619:        if (self->combattarget)
                    620:        {
                    621:                edict_t         *target;
                    622: 
                    623:                target = NULL;
                    624:                while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL)
                    625:                {
                    626:                        if (strcmp(target->classname, "point_combat") != 0)
                    627:                        {
                    628:                                gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
                    629:                                        self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2],
                    630:                                        self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1],
                    631:                                        (int)target->s.origin[2]);
                    632:                        }
                    633:                }
                    634:        }
                    635: 
                    636:        if (self->target)
                    637:        {
                    638:                self->goalentity = self->movetarget = G_PickTarget(self->target);
                    639:                if (!self->movetarget)
                    640:                {
                    641:                        gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
                    642:                        self->target = NULL;
                    643:                        self->monsterinfo.pausetime = 100000000;
                    644:                        self->monsterinfo.stand (self);
                    645:                }
                    646:                else if (strcmp (self->movetarget->classname, "path_corner") == 0)
                    647:                {
                    648:                        VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
                    649:                        self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v);
                    650:                        self->monsterinfo.walk (self);
                    651:                        self->target = NULL;
                    652:                }
                    653:                else
                    654:                {
                    655:                        self->goalentity = self->movetarget = NULL;
                    656:                        self->monsterinfo.pausetime = 100000000;
                    657:                        self->monsterinfo.stand (self);
                    658:                }
                    659:        }
                    660:        else
                    661:        {
                    662:                self->monsterinfo.pausetime = 100000000;
                    663:                self->monsterinfo.stand (self);
                    664:        }
                    665: 
                    666:        self->think = monster_think;
                    667:        self->nextthink = level.time + FRAMETIME;
                    668: }
                    669: 
                    670: 
                    671: void walkmonster_start_go (edict_t *self)
                    672: {
                    673:        if (!(self->spawnflags & 2) && level.time < 1)
                    674:        {
                    675:                M_droptofloor (self);
                    676: 
                    677:                if (self->groundentity)
                    678:                        if (!M_walkmove (self, 0, 0))
                    679:                                gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
                    680:        }
                    681:        
                    682:        if (!self->yaw_speed)
                    683:                self->yaw_speed = 20;
                    684:        self->viewheight = 25;
                    685: 
                    686:        monster_start_go (self);
                    687: 
                    688:        if (self->spawnflags & 2)
                    689:                monster_triggered_start (self);
                    690: }
                    691: 
                    692: void walkmonster_start (edict_t *self)
                    693: {
                    694:        self->think = walkmonster_start_go;
                    695:        monster_start (self);
                    696: }
                    697: 
                    698: 
                    699: void flymonster_start_go (edict_t *self)
                    700: {
                    701:        if (!M_walkmove (self, 0, 0))
                    702:                gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
                    703: 
                    704:        if (!self->yaw_speed)
                    705:                self->yaw_speed = 10;
                    706:        self->viewheight = 25;
                    707: 
                    708:        monster_start_go (self);
                    709: 
                    710:        if (self->spawnflags & 2)
                    711:                monster_triggered_start (self);
                    712: }
                    713: 
                    714: 
                    715: void flymonster_start (edict_t *self)
                    716: {
                    717:        self->flags |= FL_FLY;
                    718:        self->think = flymonster_start_go;
                    719:        monster_start (self);
                    720: }
                    721: 
                    722: 
                    723: void swimmonster_start_go (edict_t *self)
                    724: {
                    725:        if (!self->yaw_speed)
                    726:                self->yaw_speed = 10;
                    727:        self->viewheight = 10;
                    728: 
                    729:        monster_start_go (self);
                    730: 
                    731:        if (self->spawnflags & 2)
                    732:                monster_triggered_start (self);
                    733: }
                    734: 
                    735: void swimmonster_start (edict_t *self)
                    736: {
                    737:        self->flags |= FL_SWIM;
                    738:        self->think = swimmonster_start_go;
                    739:        monster_start (self);
                    740: }

unix.superglobalmegacorp.com

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