Annotation of quake2/ctf/g_trigger.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: void InitTrigger (edict_t *self)
                     24: {
                     25:        if (!VectorCompare (self->s.angles, vec3_origin))
                     26:                G_SetMovedir (self->s.angles, self->movedir);
                     27: 
                     28:        self->solid = SOLID_TRIGGER;
                     29:        self->movetype = MOVETYPE_NONE;
                     30:        gi.setmodel (self, self->model);
                     31:        self->svflags = SVF_NOCLIENT;
                     32: }
                     33: 
                     34: 
                     35: // the wait time has passed, so set back up for another activation
                     36: void multi_wait (edict_t *ent)
                     37: {
                     38:        ent->nextthink = 0;
                     39: }
                     40: 
                     41: 
                     42: // the trigger was just activated
                     43: // ent->activator should be set to the activator so it can be held through a delay
                     44: // so wait for the delay time before firing
                     45: void multi_trigger (edict_t *ent)
                     46: {
                     47:        if (ent->nextthink)
                     48:                return;         // already been triggered
                     49: 
                     50:        G_UseTargets (ent, ent->activator);
                     51: 
                     52:        if (ent->wait > 0)      
                     53:        {
                     54:                ent->think = multi_wait;
                     55:                ent->nextthink = level.time + ent->wait;
                     56:        }
                     57:        else
                     58:        {       // we can't just remove (self) here, because this is a touch function
                     59:                // called while looping through area links...
                     60:                ent->touch = NULL;
                     61:                ent->nextthink = level.time + FRAMETIME;
                     62:                ent->think = G_FreeEdict;
                     63:        }
                     64: }
                     65: 
                     66: void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator)
                     67: {
                     68:        ent->activator = activator;
                     69:        multi_trigger (ent);
                     70: }
                     71: 
                     72: void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                     73: {
                     74:        if(other->client)
                     75:        {
                     76:                if (self->spawnflags & 2)
                     77:                        return;
                     78:        }
                     79:        else if (other->svflags & SVF_MONSTER)
                     80:        {
                     81:                if (!(self->spawnflags & 1))
                     82:                        return;
                     83:        }
                     84:        else
                     85:                return;
                     86: 
                     87:        if (!VectorCompare(self->movedir, vec3_origin))
                     88:        {
                     89:                vec3_t  forward;
                     90: 
                     91:                AngleVectors(other->s.angles, forward, NULL, NULL);
                     92:                if (_DotProduct(forward, self->movedir) < 0)
                     93:                        return;
                     94:        }
                     95: 
                     96:        self->activator = other;
                     97:        multi_trigger (self);
                     98: }
                     99: 
                    100: /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
                    101: Variable sized repeatable trigger.  Must be targeted at one or more entities.
                    102: If "delay" is set, the trigger waits some time after activating before firing.
                    103: "wait" : Seconds between triggerings. (.2 default)
                    104: sounds
                    105: 1)     secret
                    106: 2)     beep beep
                    107: 3)     large switch
                    108: 4)
                    109: set "message" to text string
                    110: */
                    111: void trigger_enable (edict_t *self, edict_t *other, edict_t *activator)
                    112: {
                    113:        self->solid = SOLID_TRIGGER;
                    114:        self->use = Use_Multi;
                    115:        gi.linkentity (self);
                    116: }
                    117: 
                    118: void SP_trigger_multiple (edict_t *ent)
                    119: {
                    120:        if (ent->sounds == 1)
                    121:                ent->noise_index = gi.soundindex ("misc/secret.wav");
                    122:        else if (ent->sounds == 2)
                    123:                ent->noise_index = gi.soundindex ("misc/talk.wav");
                    124:        else if (ent->sounds == 3)
                    125:                ent->noise_index = gi.soundindex ("misc/trigger1.wav");
                    126:        
                    127:        if (!ent->wait)
                    128:                ent->wait = 0.2;
                    129:        ent->touch = Touch_Multi;
                    130:        ent->movetype = MOVETYPE_NONE;
                    131:        ent->svflags |= SVF_NOCLIENT;
                    132: 
                    133: 
                    134:        if (ent->spawnflags & 4)
                    135:        {
                    136:                ent->solid = SOLID_NOT;
                    137:                ent->use = trigger_enable;
                    138:        }
                    139:        else
                    140:        {
                    141:                ent->solid = SOLID_TRIGGER;
                    142:                ent->use = Use_Multi;
                    143:        }
                    144: 
                    145:        if (!VectorCompare(ent->s.angles, vec3_origin))
                    146:                G_SetMovedir (ent->s.angles, ent->movedir);
                    147: 
                    148:        gi.setmodel (ent, ent->model);
                    149:        gi.linkentity (ent);
                    150: }
                    151: 
                    152: 
                    153: /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
                    154: Triggers once, then removes itself.
                    155: You must set the key "target" to the name of another object in the level that has a matching "targetname".
                    156: 
                    157: If TRIGGERED, this trigger must be triggered before it is live.
                    158: 
                    159: sounds
                    160:  1)    secret
                    161:  2)    beep beep
                    162:  3)    large switch
                    163:  4)
                    164: 
                    165: "message"      string to be displayed when triggered
                    166: */
                    167: 
                    168: void SP_trigger_once(edict_t *ent)
                    169: {
                    170:        // make old maps work because I messed up on flag assignments here
                    171:        // triggered was on bit 1 when it should have been on bit 4
                    172:        if (ent->spawnflags & 1)
                    173:        {
                    174:                vec3_t  v;
                    175: 
                    176:                VectorMA (ent->mins, 0.5, ent->size, v);
                    177:                ent->spawnflags &= ~1;
                    178:                ent->spawnflags |= 4;
                    179:                gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
                    180:        }
                    181: 
                    182:        ent->wait = -1;
                    183:        SP_trigger_multiple (ent);
                    184: }
                    185: 
                    186: /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
                    187: This fixed size trigger cannot be touched, it can only be fired by other events.
                    188: */
                    189: void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator)
                    190: {
                    191:        G_UseTargets (self, activator);
                    192: }
                    193: 
                    194: void SP_trigger_relay (edict_t *self)
                    195: {
                    196:        self->use = trigger_relay_use;
                    197: }
                    198: 
                    199: 
                    200: /*
                    201: ==============================================================================
                    202: 
                    203: trigger_key
                    204: 
                    205: ==============================================================================
                    206: */
                    207: 
                    208: /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
                    209: A relay trigger that only fires it's targets if player has the proper key.
                    210: Use "item" to specify the required key, for example "key_data_cd"
                    211: */
                    212: void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
                    213: {
                    214:        int                     index;
                    215: 
                    216:        if (!self->item)
                    217:                return;
                    218:        if (!activator->client)
                    219:                return;
                    220: 
                    221:        index = ITEM_INDEX(self->item);
                    222:        if (!activator->client->pers.inventory[index])
                    223:        {
                    224:                if (level.time < self->touch_debounce_time)
                    225:                        return;
                    226:                self->touch_debounce_time = level.time + 5.0;
                    227:                gi.centerprintf (activator, "You need the %s", self->item->pickup_name);
                    228:                gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0);
                    229:                return;
                    230:        }
                    231: 
                    232:        gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0);
                    233:        if (coop->value)
                    234:        {
                    235:                int             player;
                    236:                edict_t *ent;
                    237: 
                    238:                if (strcmp(self->item->classname, "key_power_cube") == 0)
                    239:                {
                    240:                        int     cube;
                    241: 
                    242:                        for (cube = 0; cube < 8; cube++)
                    243:                                if (activator->client->pers.power_cubes & (1 << cube))
                    244:                                        break;
                    245:                        for (player = 1; player <= game.maxclients; player++)
                    246:                        {
                    247:                                ent = &g_edicts[player];
                    248:                                if (!ent->inuse)
                    249:                                        continue;
                    250:                                if (!ent->client)
                    251:                                        continue;
                    252:                                if (ent->client->pers.power_cubes & (1 << cube))
                    253:                                {
                    254:                                        ent->client->pers.inventory[index]--;
                    255:                                        ent->client->pers.power_cubes &= ~(1 << cube);
                    256:                                }
                    257:                        }
                    258:                }
                    259:                else
                    260:                {
                    261:                        for (player = 1; player <= game.maxclients; player++)
                    262:                        {
                    263:                                ent = &g_edicts[player];
                    264:                                if (!ent->inuse)
                    265:                                        continue;
                    266:                                if (!ent->client)
                    267:                                        continue;
                    268:                                ent->client->pers.inventory[index] = 0;
                    269:                        }
                    270:                }
                    271:        }
                    272:        else
                    273:        {
                    274:                activator->client->pers.inventory[index]--;
                    275:        }
                    276: 
                    277:        G_UseTargets (self, activator);
                    278: 
                    279:        self->use = NULL;
                    280: }
                    281: 
                    282: void SP_trigger_key (edict_t *self)
                    283: {
                    284:        if (!st.item)
                    285:        {
                    286:                gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
                    287:                return;
                    288:        }
                    289:        self->item = FindItemByClassname (st.item);
                    290: 
                    291:        if (!self->item)
                    292:        {
                    293:                gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
                    294:                return;
                    295:        }
                    296: 
                    297:        if (!self->target)
                    298:        {
                    299:                gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
                    300:                return;
                    301:        }
                    302: 
                    303:        gi.soundindex ("misc/keytry.wav");
                    304:        gi.soundindex ("misc/keyuse.wav");
                    305: 
                    306:        self->use = trigger_key_use;
                    307: }
                    308: 
                    309: 
                    310: /*
                    311: ==============================================================================
                    312: 
                    313: trigger_counter
                    314: 
                    315: ==============================================================================
                    316: */
                    317: 
                    318: /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
                    319: Acts as an intermediary for an action that takes multiple inputs.
                    320: 
                    321: If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
                    322: 
                    323: After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
                    324: */
                    325: 
                    326: void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
                    327: {
                    328:        if (self->count == 0)
                    329:                return;
                    330:        
                    331:        self->count--;
                    332: 
                    333:        if (self->count)
                    334:        {
                    335:                if (! (self->spawnflags & 1))
                    336:                {
                    337:                        gi.centerprintf(activator, "%i more to go...", self->count);
                    338:                        gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
                    339:                }
                    340:                return;
                    341:        }
                    342:        
                    343:        if (! (self->spawnflags & 1))
                    344:        {
                    345:                gi.centerprintf(activator, "Sequence completed!");
                    346:                gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
                    347:        }
                    348:        self->activator = activator;
                    349:        multi_trigger (self);
                    350: }
                    351: 
                    352: void SP_trigger_counter (edict_t *self)
                    353: {
                    354:        self->wait = -1;
                    355:        if (!self->count)
                    356:                self->count = 2;
                    357: 
                    358:        self->use = trigger_counter_use;
                    359: }
                    360: 
                    361: 
                    362: /*
                    363: ==============================================================================
                    364: 
                    365: trigger_always
                    366: 
                    367: ==============================================================================
                    368: */
                    369: 
                    370: /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
                    371: This trigger will always fire.  It is activated by the world.
                    372: */
                    373: void SP_trigger_always (edict_t *ent)
                    374: {
                    375:        // we must have some delay to make sure our use targets are present
                    376:        if (ent->delay < 0.2)
                    377:                ent->delay = 0.2;
                    378:        G_UseTargets(ent, ent);
                    379: }
                    380: 
                    381: 
                    382: /*
                    383: ==============================================================================
                    384: 
                    385: trigger_push
                    386: 
                    387: ==============================================================================
                    388: */
                    389: 
                    390: #define PUSH_ONCE              1
                    391: 
                    392: static int windsound;
                    393: 
                    394: void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    395: {
                    396:        if (strcmp(other->classname, "grenade") == 0)
                    397:        {
                    398:                VectorScale (self->movedir, self->speed * 10, other->velocity);
                    399:        }
                    400:        else if (other->health > 0)
                    401:        {
                    402:                VectorScale (self->movedir, self->speed * 10, other->velocity);
                    403: 
                    404:                if (other->client)
                    405:                {
                    406:                        // don't take falling damage immediately from this
                    407:                        VectorCopy (other->velocity, other->client->oldvelocity);
                    408:                        if (other->fly_sound_debounce_time < level.time)
                    409:                        {
                    410:                                other->fly_sound_debounce_time = level.time + 1.5;
                    411:                                gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
                    412:                        }
                    413:                }
                    414:        }
                    415:        if (self->spawnflags & PUSH_ONCE)
                    416:                G_FreeEdict (self);
                    417: }
                    418: 
                    419: 
                    420: /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
                    421: Pushes the player
                    422: "speed"                defaults to 1000
                    423: */
                    424: void SP_trigger_push (edict_t *self)
                    425: {
                    426:        InitTrigger (self);
                    427:        windsound = gi.soundindex ("misc/windfly.wav");
                    428:        self->touch = trigger_push_touch;
                    429:        if (!self->speed)
                    430:                self->speed = 1000;
                    431:        gi.linkentity (self);
                    432: }
                    433: 
                    434: 
                    435: /*
                    436: ==============================================================================
                    437: 
                    438: trigger_hurt
                    439: 
                    440: ==============================================================================
                    441: */
                    442: 
                    443: /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
                    444: Any entity that touches this will be hurt.
                    445: 
                    446: It does dmg points of damage each server frame
                    447: 
                    448: SILENT                 supresses playing the sound
                    449: SLOW                   changes the damage rate to once per second
                    450: NO_PROTECTION  *nothing* stops the damage
                    451: 
                    452: "dmg"                  default 5 (whole numbers only)
                    453: 
                    454: */
                    455: void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
                    456: {
                    457:        if (self->solid == SOLID_NOT)
                    458:                self->solid = SOLID_TRIGGER;
                    459:        else
                    460:                self->solid = SOLID_NOT;
                    461:        gi.linkentity (self);
                    462: 
                    463:        if (!(self->spawnflags & 2))
                    464:                self->use = NULL;
                    465: }
                    466: 
                    467: 
                    468: void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    469: {
                    470:        int             dflags;
                    471: 
                    472:        if (!other->takedamage)
                    473:                return;
                    474: 
                    475:        if (self->timestamp > level.time)
                    476:                return;
                    477: 
                    478:        if (self->spawnflags & 16)
                    479:                self->timestamp = level.time + 1;
                    480:        else
                    481:                self->timestamp = level.time + FRAMETIME;
                    482: 
                    483:        if (!(self->spawnflags & 4))
                    484:        {
                    485:                if ((level.framenum % 10) == 0)
                    486:                        gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
                    487:        }
                    488: 
                    489:        if (self->spawnflags & 8)
                    490:                dflags = DAMAGE_NO_PROTECTION;
                    491:        else
                    492:                dflags = 0;
                    493:        T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
                    494: }
                    495: 
                    496: void SP_trigger_hurt (edict_t *self)
                    497: {
                    498:        InitTrigger (self);
                    499: 
                    500:        self->noise_index = gi.soundindex ("world/electro.wav");
                    501:        self->touch = hurt_touch;
                    502: 
                    503:        if (!self->dmg)
                    504:                self->dmg = 5;
                    505: 
                    506:        if (self->spawnflags & 1)
                    507:                self->solid = SOLID_NOT;
                    508:        else
                    509:                self->solid = SOLID_TRIGGER;
                    510: 
                    511:        if (self->spawnflags & 2)
                    512:                self->use = hurt_use;
                    513: 
                    514:        gi.linkentity (self);
                    515: }
                    516: 
                    517: 
                    518: /*
                    519: ==============================================================================
                    520: 
                    521: trigger_gravity
                    522: 
                    523: ==============================================================================
                    524: */
                    525: 
                    526: /*QUAKED trigger_gravity (.5 .5 .5) ?
                    527: Changes the touching entites gravity to
                    528: the value of "gravity".  1.0 is standard
                    529: gravity for the level.
                    530: */
                    531: 
                    532: void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    533: {
                    534:        other->gravity = self->gravity;
                    535: }
                    536: 
                    537: void SP_trigger_gravity (edict_t *self)
                    538: {
                    539:        if (st.gravity == 0)
                    540:        {
                    541:                gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
                    542:                G_FreeEdict  (self);
                    543:                return;
                    544:        }
                    545: 
                    546:        InitTrigger (self);
                    547:        self->gravity = atoi(st.gravity);
                    548:        self->touch = trigger_gravity_touch;
                    549: }
                    550: 
                    551: 
                    552: /*
                    553: ==============================================================================
                    554: 
                    555: trigger_monsterjump
                    556: 
                    557: ==============================================================================
                    558: */
                    559: 
                    560: /*QUAKED trigger_monsterjump (.5 .5 .5) ?
                    561: Walking monsters that touch this will jump in the direction of the trigger's angle
                    562: "speed" default to 200, the speed thrown forward
                    563: "height" default to 200, the speed thrown upwards
                    564: */
                    565: 
                    566: void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    567: {
                    568:        if (other->flags & (FL_FLY | FL_SWIM) )
                    569:                return;
                    570:        if (other->svflags & SVF_DEADMONSTER)
                    571:                return;
                    572:        if ( !(other->svflags & SVF_MONSTER))
                    573:                return;
                    574: 
                    575: // set XY even if not on ground, so the jump will clear lips
                    576:        other->velocity[0] = self->movedir[0] * self->speed;
                    577:        other->velocity[1] = self->movedir[1] * self->speed;
                    578:        
                    579:        if (!other->groundentity)
                    580:                return;
                    581:        
                    582:        other->groundentity = NULL;
                    583:        other->velocity[2] = self->movedir[2];
                    584: }
                    585: 
                    586: void SP_trigger_monsterjump (edict_t *self)
                    587: {
                    588:        if (!self->speed)
                    589:                self->speed = 200;
                    590:        if (!st.height)
                    591:                st.height = 200;
                    592:        if (self->s.angles[YAW] == 0)
                    593:                self->s.angles[YAW] = 360;
                    594:        InitTrigger (self);
                    595:        self->touch = trigger_monsterjump_touch;
                    596:        self->movedir[2] = st.height;
                    597: }
                    598: 

unix.superglobalmegacorp.com

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