Annotation of quake2/rogue/dm_ball.c, revision 1.1.1.1

1.1       root        1: // dm_ball.c
                      2: // pmack
                      3: // june 98
                      4: 
                      5: #include "g_local.h"
                      6: 
                      7: // defines
                      8: 
                      9: #define DBALL_GOAL_TEAM1       0x0001
                     10: #define DBALL_GOAL_TEAM2       0x0002
                     11: 
                     12: // globals
                     13: 
                     14: edict_t *dball_ball_entity = NULL;
                     15: int            dball_ball_startpt_count;
                     16: int            dball_team1_goalscore;
                     17: int            dball_team2_goalscore;
                     18: 
                     19: cvar_t *dball_team1_skin;
                     20: cvar_t *dball_team2_skin;
                     21: cvar_t *goallimit;
                     22: 
                     23: // prototypes
                     24: 
                     25: extern void EndDMLevel (void);
                     26: extern void ClientUserinfoChanged (edict_t *ent, char *userinfo);
                     27: extern void    SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles);
                     28: extern float PlayersRangeFromSpot (edict_t *spot);
                     29: 
                     30: void DBall_BallDie (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
                     31: void DBall_BallRespawn (edict_t *self);
                     32: 
                     33: // **************************
                     34: // Game rules
                     35: // **************************
                     36: 
                     37: int DBall_CheckDMRules (void)
                     38: {
                     39:        if(goallimit && goallimit->value)
                     40:        {
                     41:                if(dball_team1_goalscore >= goallimit->value)
                     42:                        gi.bprintf (PRINT_HIGH, "Team 1 Wins.\n");
                     43:                else if(dball_team2_goalscore >= goallimit->value)
                     44:                        gi.bprintf (PRINT_HIGH, "Team 2 Wins.\n");
                     45:                else
                     46:                        return 0;
                     47: 
                     48:                EndDMLevel ();
                     49:                return 1;
                     50:        }
                     51: 
                     52:        return 0;
                     53: }
                     54: 
                     55: //==================
                     56: //==================
                     57: void DBall_ClientBegin (edict_t *ent)
                     58: {
                     59:        int                     team1, team2, unassigned;
                     60:        edict_t         *other;
                     61:        char            *p;
                     62:        static char     value[512];
                     63:        int                     j;
                     64: 
                     65:        team1 = 0;
                     66:        team2 = 0;
                     67:        unassigned = 0;
                     68: 
                     69:        for (j = 1; j <= game.maxclients; j++)
                     70:        {
                     71:                other = &g_edicts[j];
                     72:                if (!other->inuse)
                     73:                        continue;
                     74:                if (!other->client)
                     75:                        continue;
                     76:                if (other == ent)       // don't count the new player
                     77:                        continue;
                     78:                
                     79:                strcpy(value, Info_ValueForKey (other->client->pers.userinfo, "skin"));
                     80:                p = strchr(value, '/');
                     81:                if (p)
                     82:                {
                     83:                        if(!strcmp(dball_team1_skin->string, value))
                     84:                                team1++;
                     85:                        else if(!strcmp(dball_team2_skin->string, value))
                     86:                                team2++;
                     87:                        else
                     88:                                unassigned++;
                     89:                }
                     90:                else
                     91:                        unassigned++;
                     92:        }
                     93: 
                     94:        if(team1 > team2)
                     95:        {
                     96:                gi.dprintf("assigned to team 2\n");
                     97:                Info_SetValueForKey(ent->client->pers.userinfo, "skin", dball_team2_skin->string);
                     98:        }
                     99:        else
                    100:        {
                    101:                gi.dprintf("assigned to team 1\n");
                    102:                Info_SetValueForKey(ent->client->pers.userinfo, "skin", dball_team1_skin->string);
                    103:        }
                    104:        
                    105:        ClientUserinfoChanged(ent, ent->client->pers.userinfo);
                    106: 
                    107:        if(unassigned)
                    108:                gi.dprintf("%d unassigned players present!\n", unassigned);
                    109: }
                    110: 
                    111: //==================
                    112: //==================
                    113: void DBall_SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
                    114: {
                    115:        edict_t *bestspot;
                    116:        float   bestdistance, bestplayerdistance;
                    117:        edict_t *spot;
                    118:        char    *spottype;
                    119:        char    skin[512];
                    120: 
                    121:        strcpy(skin, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
                    122:        if(!strcmp(dball_team1_skin->string, skin))
                    123:                spottype = "dm_dball_team1_start";
                    124:        else if(!strcmp(dball_team2_skin->string, skin))
                    125:                spottype = "dm_dball_team2_start";
                    126:        else
                    127:                spottype = "info_player_deathmatch";
                    128: 
                    129:        spot = NULL;
                    130:        bestspot = NULL;
                    131:        bestdistance = 0;
                    132:        while ((spot = G_Find (spot, FOFS(classname), spottype)) != NULL)
                    133:        {
                    134:                bestplayerdistance = PlayersRangeFromSpot (spot);
                    135: 
                    136:                if (bestplayerdistance > bestdistance)
                    137:                {
                    138:                        bestspot = spot;
                    139:                        bestdistance = bestplayerdistance;
                    140:                }
                    141:        }
                    142: 
                    143:        if (bestspot)
                    144:        {
                    145:                VectorCopy (bestspot->s.origin, origin);
                    146:                origin[2] += 9;
                    147:                VectorCopy (bestspot->s.angles, angles);
                    148:                return;
                    149:        }
                    150: 
                    151:        // if we didn't find an appropriate spawnpoint, just
                    152:        // call the standard one.
                    153:        SelectSpawnPoint(ent, origin, angles);
                    154: }
                    155: 
                    156: //==================
                    157: //==================
                    158: void DBall_GameInit (void)
                    159: {
                    160:        // we don't want a minimum speed for friction to take effect.
                    161:        // this will allow any knockback to move stuff.
                    162:        sv_stopspeed->value = 0;
                    163:        dball_team1_goalscore = 0;
                    164:        dball_team2_goalscore = 0;
                    165: 
                    166:        dmflags->value = (int)dmflags->value | DF_NO_MINES | DF_NO_NUKES | DF_NO_STACK_DOUBLE | 
                    167:                                                DF_NO_FRIENDLY_FIRE | DF_SKINTEAMS;
                    168:        
                    169:        dball_team1_skin = gi.cvar ("dball_team1_skin", "male/ctf_r", 0);
                    170:        dball_team2_skin = gi.cvar ("dball_team2_skin", "male/ctf_b", 0);
                    171:        goallimit = gi.cvar ("goallimit", "0", 0);
                    172: }
                    173: 
                    174: //==================
                    175: //==================
                    176: void DBall_PostInitSetup (void)
                    177: {
                    178:        edict_t         *e;
                    179: 
                    180:        e=NULL;
                    181:        // turn teleporter destinations nonsolid.
                    182:        while(e = G_Find (e, FOFS(classname), "misc_teleporter_dest"))
                    183:        {
                    184:                e->solid = SOLID_NOT;
                    185:                gi.linkentity (e);
                    186:        }
                    187: 
                    188:        // count the ball start points
                    189:        dball_ball_startpt_count = 0;
                    190:        e=NULL;
                    191:        while(e = G_Find (e, FOFS(classname), "dm_dball_ball_start"))
                    192:        {
                    193:                dball_ball_startpt_count++;
                    194:        }
                    195: 
                    196:        if(dball_ball_startpt_count == 0)
                    197:                gi.dprintf("No Deathball start points!\n");
                    198: }
                    199: 
                    200: //==================
                    201: // DBall_ChangeDamage - half damage between players. full if it involves
                    202: //             the ball entity
                    203: //==================
                    204: int DBall_ChangeDamage (edict_t *targ, edict_t *attacker, int damage, int mod)
                    205: {
                    206:        // cut player -> ball damage to 1
                    207:        if (targ == dball_ball_entity)
                    208:                return 1;
                    209: 
                    210:        // damage player -> player is halved
                    211:        if (attacker != dball_ball_entity)
                    212:                return damage / 2;
                    213: 
                    214:        return damage;
                    215: }
                    216: 
                    217: //==================
                    218: //==================
                    219: int DBall_ChangeKnockback (edict_t *targ, edict_t *attacker, int knockback, int mod)
                    220: {
                    221:        if(targ != dball_ball_entity)
                    222:                return knockback;
                    223:        
                    224:        if(knockback < 1)
                    225:        {
                    226:                // FIXME - these don't account for quad/double
                    227:                if(mod == MOD_ROCKET)           // rocket
                    228:                        knockback = 70;
                    229:                else if(mod == MOD_BFG_EFFECT)  // bfg
                    230:                        knockback = 90;
                    231:                else
                    232:                        gi.dprintf ("zero knockback, mod %d\n", mod);
                    233:        }
                    234:        else
                    235:        {
                    236:                // FIXME - change this to an array?
                    237:                switch(mod)
                    238:                {
                    239:                        case MOD_BLASTER:
                    240:                                knockback *= 3;
                    241:                                break;
                    242:                        case MOD_SHOTGUN:
                    243:                                knockback = (knockback * 3) / 8;
                    244:                                break;
                    245:                        case MOD_SSHOTGUN:
                    246:                                knockback = knockback / 3;
                    247:                                break;
                    248:                        case MOD_MACHINEGUN:
                    249:                                knockback = (knockback * 3) / 2;
                    250:                                break;
                    251:                        case MOD_HYPERBLASTER:
                    252:                                knockback *= 4;
                    253:                                break;
                    254:                        case MOD_GRENADE:
                    255:                        case MOD_HANDGRENADE:
                    256:                        case MOD_PROX:
                    257:                        case MOD_G_SPLASH:
                    258:                        case MOD_HG_SPLASH:
                    259:                        case MOD_HELD_GRENADE:
                    260:                        case MOD_TRACKER:
                    261:                        case MOD_DISINTEGRATOR:
                    262:                                knockback /= 2;
                    263:                                break;
                    264:                        case MOD_R_SPLASH:
                    265:                                knockback = (knockback * 3) / 2;
                    266:                                break;
                    267:                        case MOD_RAILGUN:
                    268:                        case MOD_HEATBEAM:
                    269:                                knockback /= 3;
                    270:                                break;
                    271:                }
                    272:        }
                    273: 
                    274: //     gi.dprintf("mod: %d    knockback: %d\n", mod, knockback);
                    275:        return knockback;
                    276: }
                    277: 
                    278: // **************************
                    279: // Goals
                    280: // **************************
                    281: 
                    282: void DBall_GoalTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    283: {
                    284:        int             team_score;
                    285:        int             scorechange;
                    286:        int             j;
                    287:        char    value[512];
                    288:        char    *p;
                    289:        edict_t *ent;
                    290: 
                    291:        if(other != dball_ball_entity)
                    292:                return;
                    293: 
                    294:        self->health = self->max_health;
                    295: 
                    296:        // determine which team scored, and bump the team score
                    297:        if(self->spawnflags & DBALL_GOAL_TEAM1)
                    298:        {
                    299:                dball_team1_goalscore += self->wait;            
                    300:                team_score = 1;
                    301:        }
                    302:        else
                    303:        {
                    304:                dball_team2_goalscore += self->wait;            
                    305:                team_score = 2;
                    306:        }
                    307: 
                    308:        // bump the score for everyone on the correct team.
                    309:        for (j = 1; j <= game.maxclients; j++)
                    310:        {
                    311:                ent = &g_edicts[j];
                    312:                if (!ent->inuse)
                    313:                        continue;
                    314:                if (!ent->client)
                    315:                        continue;
                    316:                
                    317:                if (ent == other->enemy)
                    318:                        scorechange = self->wait + 5;
                    319:                else
                    320:                        scorechange = self->wait;
                    321: 
                    322:                strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
                    323:                p = strchr(value, '/');
                    324:                if (p)
                    325:                {
                    326:                        if(!strcmp(dball_team1_skin->string, value))
                    327:                        {
                    328:                                if(team_score == 1)
                    329:                                        ent->client->resp.score += scorechange;
                    330:                                else if(other->enemy == ent)
                    331:                                        ent->client->resp.score -= scorechange;
                    332:                        }
                    333:                        else if(!strcmp(dball_team2_skin->string, value))
                    334:                        {
                    335:                                if(team_score == 2)
                    336:                                        ent->client->resp.score += scorechange;
                    337:                                else if(other->enemy == ent)
                    338:                                        ent->client->resp.score -= scorechange;
                    339:                        }
                    340:                        else
                    341:                                gi.dprintf("unassigned player!!!!\n");
                    342:                }
                    343:        }
                    344: 
                    345:        if(other->enemy)
                    346:                gi.dprintf("score for team %d by %s\n", team_score, other->enemy->client->pers.netname);
                    347:        else
                    348:                gi.dprintf("score for team %d by someone\n", team_score);
                    349: 
                    350:        DBall_BallDie (other, other->enemy, other->enemy, 0, vec3_origin);
                    351: 
                    352:        G_UseTargets (self, other);
                    353: }
                    354: 
                    355: // **************************
                    356: // Ball
                    357: // **************************
                    358: 
                    359: edict_t *PickBallStart (edict_t *ent)
                    360: {
                    361:        int             which, current;
                    362:        edict_t *e;
                    363: 
                    364:        which = ceil(random() * dball_ball_startpt_count);
                    365:        e = NULL;
                    366:        current = 0;
                    367: 
                    368:        while(e = G_Find (e, FOFS(classname), "dm_dball_ball_start"))
                    369:        {
                    370:                current++;
                    371:                if(current == which)
                    372:                        return e;
                    373:        }
                    374: 
                    375:        if(current == 0)
                    376:                gi.dprintf("No ball start points found!\n");
                    377: 
                    378:        return G_Find(NULL, FOFS(classname), "dm_dball_ball_start");
                    379: }
                    380: 
                    381: //==================
                    382: // DBall_BallTouch - if the ball hit another player, hurt them
                    383: //==================
                    384: void DBall_BallTouch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
                    385: {
                    386:        vec3_t  dir;
                    387:        float   dot;
                    388:        float   speed;
                    389: 
                    390:        if(other->takedamage == DAMAGE_NO)
                    391:                return;
                    392: 
                    393:        // hit a player
                    394:        if(other->client) 
                    395:        {
                    396:                if(ent->velocity[0] || ent->velocity[1] || ent->velocity[2])
                    397:                {
                    398:                        speed = VectorLength(ent->velocity);
                    399: 
                    400:                        VectorSubtract(ent->s.origin, other->s.origin, dir);
                    401:                        dot = DotProduct(dir, ent->velocity);
                    402: 
                    403:                        if(dot > 0.7)
                    404:                        {
                    405:                                T_Damage (other, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 
                    406:                                                speed/10, speed/10, 0, MOD_DBALL_CRUSH);
                    407:                        }
                    408:                }
                    409:        }
                    410: }
                    411: 
                    412: //==================
                    413: // DBall_BallPain
                    414: //==================
                    415: void DBall_BallPain (edict_t *self, edict_t *other, float kick, int damage)
                    416: {
                    417:        self->enemy = other;
                    418:        self->health = self->max_health;
                    419: //     if(other->classname)
                    420: //             gi.dprintf("hurt by %s -- %d\n", other->classname, self->health);
                    421: }
                    422: 
                    423: void DBall_BallDie (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                    424: {
                    425:        // do the splash effect
                    426:        gi.WriteByte (svc_temp_entity);
                    427:        gi.WriteByte (TE_DBALL_GOAL);
                    428:        gi.WritePosition (self->s.origin);
                    429:        gi.multicast (self->s.origin, MULTICAST_PVS);
                    430: 
                    431:        VectorClear(self->s.angles);
                    432:        VectorClear(self->velocity);
                    433:        VectorClear(self->avelocity);
                    434: 
                    435:        // make it invisible and desolid until respawn time
                    436:        self->solid = SOLID_NOT;
                    437: //     self->s.modelindex = 0;
                    438:        self->think = DBall_BallRespawn;
                    439:        self->nextthink = level.time + 2;
                    440:        gi.linkentity(self);
                    441: 
                    442: }
                    443: 
                    444: void DBall_BallRespawn (edict_t *self)
                    445: {
                    446:        edict_t         *start;
                    447: 
                    448:        // do the splash effect
                    449:        gi.WriteByte (svc_temp_entity);
                    450:        gi.WriteByte (TE_DBALL_GOAL);
                    451:        gi.WritePosition (self->s.origin);
                    452:        gi.multicast (self->s.origin, MULTICAST_PVS);
                    453: 
                    454:        // move the ball and stop it
                    455:        start = PickBallStart(self);
                    456:        if(start)
                    457:        {
                    458:                VectorCopy(start->s.origin, self->s.origin);
                    459:                VectorCopy(start->s.origin, self->s.old_origin);
                    460:        }
                    461: 
                    462:        VectorClear(self->s.angles);
                    463:        VectorClear(self->velocity);
                    464:        VectorClear(self->avelocity);
                    465:        
                    466:        self->solid = SOLID_BBOX;
                    467:        self->s.modelindex = gi.modelindex ("models/objects/dball/tris.md2");
                    468:        self->s.event = EV_PLAYER_TELEPORT;
                    469:        self->groundentity = NULL;
                    470: 
                    471:        // kill anything at the destination
                    472:        KillBox (self);
                    473: 
                    474:        gi.linkentity (self);
                    475: }
                    476: 
                    477: // ************************
                    478: // SPEED CHANGES
                    479: // ************************
                    480: 
                    481: #define DBALL_SPEED_ONEWAY             1
                    482: 
                    483: void DBall_SpeedTouch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    484: {
                    485:        float   dot;
                    486:        vec3_t  vel;
                    487: 
                    488:        if(other != dball_ball_entity)
                    489:                return;
                    490: 
                    491:        if(self->timestamp >= level.time)
                    492:                return;
                    493: 
                    494:        if(VectorLength(other->velocity) < 1)
                    495:                return;
                    496: 
                    497:        if(self->spawnflags & DBALL_SPEED_ONEWAY)
                    498:        {
                    499:                VectorCopy (other->velocity, vel);
                    500:                VectorNormalize (vel);
                    501:                dot = DotProduct (vel, self->movedir);
                    502:                if(dot < 0.8)
                    503:                        return;
                    504:        }
                    505: 
                    506:        self->timestamp = level.time + self->delay;
                    507:        VectorScale (other->velocity, self->speed, other->velocity);
                    508: }
                    509: 
                    510: // ************************
                    511: // SPAWN FUNCTIONS
                    512: // ************************
                    513: 
                    514: /*QUAKED dm_dball_ball (1 .5 .5) (-48 -48 -48) (48 48 48)
                    515: Deathball Ball
                    516: */
                    517: void SP_dm_dball_ball (edict_t *self)
                    518: {
                    519:        if(!(deathmatch->value))
                    520:        {
                    521:                G_FreeEdict(self);      
                    522:                return;
                    523:        }
                    524: 
                    525:        if(gamerules && (gamerules->value != RDM_DEATHBALL))
                    526:        {
                    527:                G_FreeEdict(self);      
                    528:                return;
                    529:        }
                    530: 
                    531:        dball_ball_entity = self;
                    532: //     VectorCopy (self->s.origin, dball_ball_startpt);
                    533: 
                    534:        self->s.modelindex = gi.modelindex ("models/objects/dball/tris.md2");
                    535:        VectorSet (self->mins, -32, -32, -32);
                    536:        VectorSet (self->maxs, 32, 32, 32);
                    537:        self->solid = SOLID_BBOX;
                    538:        self->movetype = MOVETYPE_NEWTOSS;
                    539:        self->clipmask = MASK_MONSTERSOLID;
                    540: 
                    541:        self->takedamage = DAMAGE_YES;
                    542:        self->mass = 50;
                    543:        self->health = 50000;
                    544:        self->max_health = 50000;
                    545:        self->pain = DBall_BallPain;
                    546:        self->die = DBall_BallDie;
                    547:        self->touch = DBall_BallTouch;
                    548: 
                    549:        gi.linkentity (self);
                    550: }
                    551: 
                    552: /*QUAKED dm_dball_team1_start (1 .5 .5) (-16 -16 -24) (16 16 32)
                    553: Deathball team 1 start point
                    554: */
                    555: void SP_dm_dball_team1_start (edict_t *self)
                    556: {
                    557:        if (!deathmatch->value)
                    558:        {
                    559:                G_FreeEdict (self);
                    560:                return;
                    561:        }
                    562:        if(gamerules && (gamerules->value != RDM_DEATHBALL))
                    563:        {
                    564:                G_FreeEdict(self);      
                    565:                return;
                    566:        }
                    567: }
                    568: 
                    569: /*QUAKED dm_dball_team2_start (1 .5 .5) (-16 -16 -24) (16 16 32)
                    570: Deathball team 2 start point
                    571: */
                    572: void SP_dm_dball_team2_start (edict_t *self)
                    573: {
                    574:        if (!deathmatch->value)
                    575:        {
                    576:                G_FreeEdict (self);
                    577:                return;
                    578:        }
                    579:        if(gamerules && (gamerules->value != RDM_DEATHBALL))
                    580:        {
                    581:                G_FreeEdict(self);      
                    582:                return;
                    583:        }
                    584: }
                    585: 
                    586: /*QUAKED dm_dball_ball_start (1 .5 .5) (-48 -48 -48) (48 48 48)
                    587: Deathball ball start point
                    588: */
                    589: void SP_dm_dball_ball_start (edict_t *self)
                    590: {
                    591:        if (!deathmatch->value)
                    592:        {
                    593:                G_FreeEdict (self);
                    594:                return;
                    595:        }
                    596:        if(gamerules && (gamerules->value != RDM_DEATHBALL))
                    597:        {
                    598:                G_FreeEdict(self);      
                    599:                return;
                    600:        }
                    601: }
                    602: 
                    603: /*QUAKED dm_dball_speed_change (1 .5 .5) ? ONEWAY
                    604: Deathball ball speed changing field.
                    605: 
                    606: speed: multiplier for speed (.5 = half, 2 = double, etc) (default = double)
                    607: angle: used with ONEWAY so speed change is only one way.
                    608: delay: time between speed changes (default: 0.2 sec)
                    609: */
                    610: void SP_dm_dball_speed_change (edict_t *self)
                    611: {
                    612:        if (!deathmatch->value)
                    613:        {
                    614:                G_FreeEdict (self);
                    615:                return;
                    616:        }
                    617:        if(gamerules && (gamerules->value != RDM_DEATHBALL))
                    618:        {
                    619:                G_FreeEdict(self);      
                    620:                return;
                    621:        }
                    622: 
                    623:        if(!self->speed)
                    624:                self->speed = 2;
                    625: 
                    626:        if(!self->delay)
                    627:                self->delay = 0.2;
                    628: 
                    629:        self->touch = DBall_SpeedTouch;
                    630:        self->solid = SOLID_TRIGGER;
                    631:        self->movetype = MOVETYPE_NONE;
                    632:        self->svflags |= SVF_NOCLIENT;
                    633: 
                    634:        if (!VectorCompare(self->s.angles, vec3_origin))
                    635:                G_SetMovedir (self->s.angles, self->movedir);
                    636:        else
                    637:                VectorSet (self->movedir, 1, 0, 0);
                    638: 
                    639:        gi.setmodel (self, self->model);
                    640:        gi.linkentity (self);
                    641: }
                    642: 
                    643: /*QUAKED dm_dball_goal (1 .5 .5) ? TEAM1 TEAM2
                    644: Deathball goal
                    645: 
                    646: Team1/Team2 - beneficiary of this goal. when the ball enters this goal, the beneficiary team will score.
                    647: 
                    648: "wait": score to be given for this goal (default 10) player gets score+5.
                    649: */
                    650: void SP_dm_dball_goal (edict_t *self)
                    651: {
                    652:        if(!(deathmatch->value))
                    653:        {
                    654:                G_FreeEdict(self);      
                    655:                return;
                    656:        }
                    657: 
                    658:        if(gamerules && (gamerules->value != RDM_DEATHBALL))
                    659:        {
                    660:                G_FreeEdict(self);      
                    661:                return;
                    662:        }
                    663: 
                    664:        if(!self->wait)
                    665:                self->wait = 10;
                    666: 
                    667:        self->touch = DBall_GoalTouch;
                    668:        self->solid = SOLID_TRIGGER;
                    669:        self->movetype = MOVETYPE_NONE;
                    670:        self->svflags |= SVF_NOCLIENT;
                    671: 
                    672:        if (!VectorCompare(self->s.angles, vec3_origin))
                    673:                G_SetMovedir (self->s.angles, self->movedir);
                    674: 
                    675:        gi.setmodel (self, self->model);
                    676:        gi.linkentity (self);
                    677: 
                    678: }

unix.superglobalmegacorp.com

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