Annotation of quake2/game/g_target.c, revision 1.1.1.3

1.1.1.3 ! 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: /*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
                     23: Fire an origin based temp entity event to the clients.
                     24: "style"                type byte
                     25: */
                     26: void Use_Target_Tent (edict_t *ent, edict_t *other, edict_t *activator)
                     27: {
                     28:        gi.WriteByte (svc_temp_entity);
                     29:        gi.WriteByte (ent->style);
                     30:        gi.WritePosition (ent->s.origin);
                     31:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                     32: }
                     33: 
                     34: void SP_target_temp_entity (edict_t *ent)
                     35: {
                     36:        ent->use = Use_Target_Tent;
                     37: }
                     38: 
                     39: 
                     40: //==========================================================
                     41: 
                     42: //==========================================================
                     43: 
                     44: /*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable
                     45: "noise"                wav file to play
                     46: "attenuation"
                     47: -1 = none, send to whole level
                     48: 1 = normal fighting sounds
                     49: 2 = idle sound level
                     50: 3 = ambient sound level
                     51: "volume"       0.0 to 1.0
                     52: 
                     53: Normal sounds play each time the target is used.  The reliable flag can be set for crucial voiceovers.
                     54: 
                     55: Looped sounds are always atten 3 / vol 1, and the use function toggles it on/off.
                     56: Multiple identical looping sounds will just increase volume without any speed cost.
                     57: */
                     58: void Use_Target_Speaker (edict_t *ent, edict_t *other, edict_t *activator)
                     59: {
                     60:        int             chan;
                     61: 
                     62:        if (ent->spawnflags & 3)
                     63:        {       // looping sound toggles
                     64:                if (ent->s.sound)
                     65:                        ent->s.sound = 0;       // turn it off
                     66:                else
                     67:                        ent->s.sound = ent->noise_index;        // start it
                     68:        }
                     69:        else
                     70:        {       // normal sound
                     71:                if (ent->spawnflags & 4)
                     72:                        chan = CHAN_VOICE|CHAN_RELIABLE;
                     73:                else
                     74:                        chan = CHAN_VOICE;
                     75:                // use a positioned_sound, because this entity won't normally be
                     76:                // sent to any clients because it is invisible
                     77:                gi.positioned_sound (ent->s.origin, ent, chan, ent->noise_index, ent->volume, ent->attenuation, 0);
                     78:        }
                     79: }
                     80: 
                     81: void SP_target_speaker (edict_t *ent)
                     82: {
                     83:        char    buffer[MAX_QPATH];
                     84: 
                     85:        if(!st.noise)
                     86:        {
                     87:                gi.dprintf("target_speaker with no noise set at %s\n", vtos(ent->s.origin));
                     88:                return;
                     89:        }
                     90:        if (!strstr (st.noise, ".wav"))
                     91:                Com_sprintf (buffer, sizeof(buffer), "%s.wav", st.noise);
                     92:        else
                     93:                strncpy (buffer, st.noise, sizeof(buffer));
                     94:        ent->noise_index = gi.soundindex (buffer);
                     95: 
                     96:        if (!ent->volume)
                     97:                ent->volume = 1.0;
                     98: 
                     99:        if (!ent->attenuation)
                    100:                ent->attenuation = 1.0;
                    101:        else if (ent->attenuation == -1)        // use -1 so 0 defaults to 1
                    102:                ent->attenuation = 0;
                    103: 
                    104:        // check for prestarted looping sound
                    105:        if (ent->spawnflags & 1)
                    106:                ent->s.sound = ent->noise_index;
                    107: 
                    108:        ent->use = Use_Target_Speaker;
                    109: 
                    110:        // must link the entity so we get areas and clusters so
                    111:        // the server can determine who to send updates to
                    112:        gi.linkentity (ent);
                    113: }
                    114: 
                    115: 
                    116: //==========================================================
                    117: 
                    118: void Use_Target_Help (edict_t *ent, edict_t *other, edict_t *activator)
                    119: {
                    120:        if (ent->spawnflags & 1)
                    121:                strncpy (game.helpmessage1, ent->message, sizeof(game.helpmessage2)-1);
                    122:        else
                    123:                strncpy (game.helpmessage2, ent->message, sizeof(game.helpmessage1)-1);
                    124: 
                    125:        game.helpchanged++;
                    126: }
                    127: 
                    128: /*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1
                    129: When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars.
                    130: */
                    131: void SP_target_help(edict_t *ent)
                    132: {
                    133:        if (deathmatch->value)
                    134:        {       // auto-remove for deathmatch
                    135:                G_FreeEdict (ent);
                    136:                return;
                    137:        }
                    138: 
                    139:        if (!ent->message)
                    140:        {
                    141:                gi.dprintf ("%s with no message at %s\n", ent->classname, vtos(ent->s.origin));
                    142:                G_FreeEdict (ent);
                    143:                return;
                    144:        }
                    145:        ent->use = Use_Target_Help;
                    146: }
                    147: 
                    148: //==========================================================
                    149: 
                    150: /*QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8)
                    151: Counts a secret found.
                    152: These are single use targets.
                    153: */
                    154: void use_target_secret (edict_t *ent, edict_t *other, edict_t *activator)
                    155: {
                    156:        gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
                    157: 
                    158:        level.found_secrets++;
                    159: 
                    160:        G_UseTargets (ent, activator);
                    161:        G_FreeEdict (ent);
                    162: }
                    163: 
                    164: void SP_target_secret (edict_t *ent)
                    165: {
                    166:        if (deathmatch->value)
                    167:        {       // auto-remove for deathmatch
                    168:                G_FreeEdict (ent);
                    169:                return;
                    170:        }
                    171: 
                    172:        ent->use = use_target_secret;
                    173:        if (!st.noise)
                    174:                st.noise = "misc/secret.wav";
                    175:        ent->noise_index = gi.soundindex (st.noise);
                    176:        ent->svflags = SVF_NOCLIENT;
                    177:        level.total_secrets++;
                    178:        // map bug hack
1.1.1.2   root      179:        if (!Q_stricmp(level.mapname, "mine3") && ent->s.origin[0] == 280 && ent->s.origin[1] == -2048 && ent->s.origin[2] == -624)
1.1       root      180:                ent->message = "You have found a secret area.";
                    181: }
                    182: 
                    183: //==========================================================
                    184: 
                    185: /*QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8)
                    186: Counts a goal completed.
                    187: These are single use targets.
                    188: */
                    189: void use_target_goal (edict_t *ent, edict_t *other, edict_t *activator)
                    190: {
                    191:        gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
                    192: 
                    193:        level.found_goals++;
                    194: 
                    195:        if (level.found_goals == level.total_goals)
                    196:                gi.configstring (CS_CDTRACK, "0");
                    197: 
                    198:        G_UseTargets (ent, activator);
                    199:        G_FreeEdict (ent);
                    200: }
                    201: 
                    202: void SP_target_goal (edict_t *ent)
                    203: {
                    204:        if (deathmatch->value)
                    205:        {       // auto-remove for deathmatch
                    206:                G_FreeEdict (ent);
                    207:                return;
                    208:        }
                    209: 
                    210:        ent->use = use_target_goal;
                    211:        if (!st.noise)
                    212:                st.noise = "misc/secret.wav";
                    213:        ent->noise_index = gi.soundindex (st.noise);
                    214:        ent->svflags = SVF_NOCLIENT;
                    215:        level.total_goals++;
                    216: }
                    217: 
                    218: //==========================================================
                    219: 
                    220: 
                    221: /*QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8)
                    222: Spawns an explosion temporary entity when used.
                    223: 
                    224: "delay"                wait this long before going off
                    225: "dmg"          how much radius damage should be done, defaults to 0
                    226: */
                    227: void target_explosion_explode (edict_t *self)
                    228: {
                    229:        float           save;
                    230: 
                    231:        gi.WriteByte (svc_temp_entity);
                    232:        gi.WriteByte (TE_EXPLOSION1);
                    233:        gi.WritePosition (self->s.origin);
                    234:        gi.multicast (self->s.origin, MULTICAST_PHS);
                    235: 
                    236:        T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
                    237: 
                    238:        save = self->delay;
                    239:        self->delay = 0;
                    240:        G_UseTargets (self, self->activator);
                    241:        self->delay = save;
                    242: }
                    243: 
                    244: void use_target_explosion (edict_t *self, edict_t *other, edict_t *activator)
                    245: {
                    246:        self->activator = activator;
                    247: 
                    248:        if (!self->delay)
                    249:        {
                    250:                target_explosion_explode (self);
                    251:                return;
                    252:        }
                    253: 
                    254:        self->think = target_explosion_explode;
                    255:        self->nextthink = level.time + self->delay;
                    256: }
                    257: 
                    258: void SP_target_explosion (edict_t *ent)
                    259: {
                    260:        ent->use = use_target_explosion;
                    261:        ent->svflags = SVF_NOCLIENT;
                    262: }
                    263: 
                    264: 
                    265: //==========================================================
                    266: 
                    267: /*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8)
                    268: Changes level to "map" when fired
                    269: */
                    270: void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator)
                    271: {
                    272:        if (level.intermissiontime)
                    273:                return;         // already activated
                    274: 
                    275:        if (!deathmatch->value && !coop->value)
                    276:        {
                    277:                if (g_edicts[1].health <= 0)
                    278:                        return;
                    279:        }
                    280: 
                    281:        // if noexit, do a ton of damage to other
                    282:        if (deathmatch->value && !( (int)dmflags->value & DF_ALLOW_EXIT) && other != world)
                    283:        {
                    284:                T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 10 * other->max_health, 1000, 0, MOD_EXIT);
                    285:                return;
                    286:        }
                    287: 
                    288:        // if multiplayer, let everyone know who hit the exit
                    289:        if (deathmatch->value)
                    290:        {
                    291:                if (activator && activator->client)
                    292:                        gi.bprintf (PRINT_HIGH, "%s exited the level.\n", activator->client->pers.netname);
                    293:        }
                    294: 
                    295:        // if going to a new unit, clear cross triggers
                    296:        if (strstr(self->map, "*"))     
                    297:                game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK);
                    298: 
                    299:        BeginIntermission (self);
                    300: }
                    301: 
                    302: void SP_target_changelevel (edict_t *ent)
                    303: {
                    304:        if (!ent->map)
                    305:        {
                    306:                gi.dprintf("target_changelevel with no map at %s\n", vtos(ent->s.origin));
                    307:                G_FreeEdict (ent);
                    308:                return;
                    309:        }
                    310: 
                    311:        // ugly hack because *SOMEBODY* screwed up their map
1.1.1.2   root      312:    if((Q_stricmp(level.mapname, "fact1") == 0) && (Q_stricmp(ent->map, "fact3") == 0))
1.1       root      313:           ent->map = "fact3$secret1";
                    314: 
                    315:        ent->use = use_target_changelevel;
                    316:        ent->svflags = SVF_NOCLIENT;
                    317: }
                    318: 
                    319: 
                    320: //==========================================================
                    321: 
                    322: /*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8)
                    323: Creates a particle splash effect when used.
                    324: 
                    325: Set "sounds" to one of the following:
                    326:   1) sparks
                    327:   2) blue water
                    328:   3) brown water
                    329:   4) slime
                    330:   5) lava
                    331:   6) blood
                    332: 
                    333: "count"        how many pixels in the splash
                    334: "dmg"  if set, does a radius damage at this location when it splashes
                    335:                useful for lava/sparks
                    336: */
                    337: 
                    338: void use_target_splash (edict_t *self, edict_t *other, edict_t *activator)
                    339: {
                    340:        gi.WriteByte (svc_temp_entity);
                    341:        gi.WriteByte (TE_SPLASH);
                    342:        gi.WriteByte (self->count);
                    343:        gi.WritePosition (self->s.origin);
                    344:        gi.WriteDir (self->movedir);
                    345:        gi.WriteByte (self->sounds);
                    346:        gi.multicast (self->s.origin, MULTICAST_PVS);
                    347: 
                    348:        if (self->dmg)
                    349:                T_RadiusDamage (self, activator, self->dmg, NULL, self->dmg+40, MOD_SPLASH);
                    350: }
                    351: 
                    352: void SP_target_splash (edict_t *self)
                    353: {
                    354:        self->use = use_target_splash;
                    355:        G_SetMovedir (self->s.angles, self->movedir);
                    356: 
                    357:        if (!self->count)
                    358:                self->count = 32;
                    359: 
                    360:        self->svflags = SVF_NOCLIENT;
                    361: }
                    362: 
                    363: 
                    364: //==========================================================
                    365: 
                    366: /*QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8)
                    367: Set target to the type of entity you want spawned.
                    368: Useful for spawning monsters and gibs in the factory levels.
                    369: 
                    370: For monsters:
                    371:        Set direction to the facing you want it to have.
                    372: 
                    373: For gibs:
                    374:        Set direction if you want it moving and
                    375:        speed how fast it should be moving otherwise it
                    376:        will just be dropped
                    377: */
                    378: void ED_CallSpawn (edict_t *ent);
                    379: 
                    380: void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator)
                    381: {
                    382:        edict_t *ent;
                    383: 
                    384:        ent = G_Spawn();
                    385:        ent->classname = self->target;
                    386:        VectorCopy (self->s.origin, ent->s.origin);
                    387:        VectorCopy (self->s.angles, ent->s.angles);
                    388:        ED_CallSpawn (ent);
                    389:        gi.unlinkentity (ent);
                    390:        KillBox (ent);
                    391:        gi.linkentity (ent);
                    392:        if (self->speed)
                    393:                VectorCopy (self->movedir, ent->velocity);
                    394: }
                    395: 
                    396: void SP_target_spawner (edict_t *self)
                    397: {
                    398:        self->use = use_target_spawner;
                    399:        self->svflags = SVF_NOCLIENT;
                    400:        if (self->speed)
                    401:        {
                    402:                G_SetMovedir (self->s.angles, self->movedir);
                    403:                VectorScale (self->movedir, self->speed, self->movedir);
                    404:        }
                    405: }
                    406: 
                    407: //==========================================================
                    408: 
                    409: /*QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS
                    410: Fires a blaster bolt in the set direction when triggered.
                    411: 
                    412: dmg            default is 15
                    413: speed  default is 1000
                    414: */
                    415: 
                    416: void use_target_blaster (edict_t *self, edict_t *other, edict_t *activator)
                    417: {
                    418:        int effect;
                    419: 
                    420:        if (self->spawnflags & 2)
                    421:                effect = 0;
                    422:        else if (self->spawnflags & 1)
                    423:                effect = EF_HYPERBLASTER;
                    424:        else
                    425:                effect = EF_BLASTER;
                    426: 
                    427:        fire_blaster (self, self->s.origin, self->movedir, self->dmg, self->speed, EF_BLASTER, MOD_TARGET_BLASTER);
                    428:        gi.sound (self, CHAN_VOICE, self->noise_index, 1, ATTN_NORM, 0);
                    429: }
                    430: 
                    431: void SP_target_blaster (edict_t *self)
                    432: {
                    433:        self->use = use_target_blaster;
                    434:        G_SetMovedir (self->s.angles, self->movedir);
                    435:        self->noise_index = gi.soundindex ("weapons/laser2.wav");
                    436: 
                    437:        if (!self->dmg)
                    438:                self->dmg = 15;
                    439:        if (!self->speed)
                    440:                self->speed = 1000;
                    441: 
                    442:        self->svflags = SVF_NOCLIENT;
                    443: }
                    444: 
                    445: 
                    446: //==========================================================
                    447: 
                    448: /*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
                    449: Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit.  It is OK to check multiple triggers.  Message, delay, target, and killtarget also work.
                    450: */
                    451: void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator)
                    452: {
                    453:        game.serverflags |= self->spawnflags;
                    454:        G_FreeEdict (self);
                    455: }
                    456: 
                    457: void SP_target_crosslevel_trigger (edict_t *self)
                    458: {
                    459:        self->svflags = SVF_NOCLIENT;
                    460:        self->use = trigger_crosslevel_trigger_use;
                    461: }
                    462: 
                    463: /*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
                    464: Triggered by a trigger_crosslevel elsewhere within a unit.  If multiple triggers are checked, all must be true.  Delay, target and
                    465: killtarget also work.
                    466: 
                    467: "delay"                delay before using targets if the trigger has been activated (default 1)
                    468: */
                    469: void target_crosslevel_target_think (edict_t *self)
                    470: {
                    471:        if (self->spawnflags == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self->spawnflags))
                    472:        {
                    473:                G_UseTargets (self, self);
                    474:                G_FreeEdict (self);
                    475:        }
                    476: }
                    477: 
                    478: void SP_target_crosslevel_target (edict_t *self)
                    479: {
                    480:        if (! self->delay)
                    481:                self->delay = 1;
                    482:        self->svflags = SVF_NOCLIENT;
                    483: 
                    484:        self->think = target_crosslevel_target_think;
                    485:        self->nextthink = level.time + self->delay;
                    486: }
                    487: 
                    488: //==========================================================
                    489: 
                    490: /*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT
                    491: When triggered, fires a laser.  You can either set a target
                    492: or a direction.
                    493: */
                    494: 
                    495: void target_laser_think (edict_t *self)
                    496: {
                    497:        edict_t *ignore;
                    498:        vec3_t  start;
                    499:        vec3_t  end;
                    500:        trace_t tr;
                    501:        vec3_t  point;
                    502:        vec3_t  last_movedir;
                    503:        int             count;
                    504: 
                    505:        if (self->spawnflags & 0x80000000)
                    506:                count = 8;
                    507:        else
                    508:                count = 4;
                    509: 
                    510:        if (self->enemy)
                    511:        {
                    512:                VectorCopy (self->movedir, last_movedir);
                    513:                VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
                    514:                VectorSubtract (point, self->s.origin, self->movedir);
                    515:                VectorNormalize (self->movedir);
                    516:                if (!VectorCompare(self->movedir, last_movedir))
                    517:                        self->spawnflags |= 0x80000000;
                    518:        }
                    519: 
                    520:        ignore = self;
                    521:        VectorCopy (self->s.origin, start);
                    522:        VectorMA (start, 2048, self->movedir, end);
                    523:        while(1)
                    524:        {
                    525:                tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
                    526: 
                    527:                if (!tr.ent)
                    528:                        break;
                    529: 
                    530:                // hurt it if we can
                    531:                if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER))
                    532:                        T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER);
                    533: 
                    534:                // if we hit something that's not a monster or player or is immune to lasers, we're done
                    535:                if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
                    536:                {
                    537:                        if (self->spawnflags & 0x80000000)
                    538:                        {
                    539:                                self->spawnflags &= ~0x80000000;
                    540:                                gi.WriteByte (svc_temp_entity);
                    541:                                gi.WriteByte (TE_LASER_SPARKS);
                    542:                                gi.WriteByte (count);
                    543:                                gi.WritePosition (tr.endpos);
                    544:                                gi.WriteDir (tr.plane.normal);
                    545:                                gi.WriteByte (self->s.skinnum);
                    546:                                gi.multicast (tr.endpos, MULTICAST_PVS);
                    547:                        }
                    548:                        break;
                    549:                }
                    550: 
                    551:                ignore = tr.ent;
                    552:                VectorCopy (tr.endpos, start);
                    553:        }
                    554: 
                    555:        VectorCopy (tr.endpos, self->s.old_origin);
                    556: 
                    557:        self->nextthink = level.time + FRAMETIME;
                    558: }
                    559: 
                    560: void target_laser_on (edict_t *self)
                    561: {
                    562:        if (!self->activator)
                    563:                self->activator = self;
                    564:        self->spawnflags |= 0x80000001;
                    565:        self->svflags &= ~SVF_NOCLIENT;
                    566:        target_laser_think (self);
                    567: }
                    568: 
                    569: void target_laser_off (edict_t *self)
                    570: {
                    571:        self->spawnflags &= ~1;
                    572:        self->svflags |= SVF_NOCLIENT;
                    573:        self->nextthink = 0;
                    574: }
                    575: 
                    576: void target_laser_use (edict_t *self, edict_t *other, edict_t *activator)
                    577: {
                    578:        self->activator = activator;
                    579:        if (self->spawnflags & 1)
                    580:                target_laser_off (self);
                    581:        else
                    582:                target_laser_on (self);
                    583: }
                    584: 
                    585: void target_laser_start (edict_t *self)
                    586: {
                    587:        edict_t *ent;
                    588: 
                    589:        self->movetype = MOVETYPE_NONE;
                    590:        self->solid = SOLID_NOT;
                    591:        self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT;
                    592:        self->s.modelindex = 1;                 // must be non-zero
                    593: 
                    594:        // set the beam diameter
                    595:        if (self->spawnflags & 64)
                    596:                self->s.frame = 16;
                    597:        else
                    598:                self->s.frame = 4;
                    599: 
                    600:        // set the color
                    601:        if (self->spawnflags & 2)
                    602:                self->s.skinnum = 0xf2f2f0f0;
                    603:        else if (self->spawnflags & 4)
                    604:                self->s.skinnum = 0xd0d1d2d3;
                    605:        else if (self->spawnflags & 8)
                    606:                self->s.skinnum = 0xf3f3f1f1;
                    607:        else if (self->spawnflags & 16)
                    608:                self->s.skinnum = 0xdcdddedf;
                    609:        else if (self->spawnflags & 32)
                    610:                self->s.skinnum = 0xe0e1e2e3;
                    611: 
                    612:        if (!self->enemy)
                    613:        {
                    614:                if (self->target)
                    615:                {
                    616:                        ent = G_Find (NULL, FOFS(targetname), self->target);
                    617:                        if (!ent)
                    618:                                gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
                    619:                        self->enemy = ent;
                    620:                }
                    621:                else
                    622:                {
                    623:                        G_SetMovedir (self->s.angles, self->movedir);
                    624:                }
                    625:        }
                    626:        self->use = target_laser_use;
                    627:        self->think = target_laser_think;
                    628: 
                    629:        if (!self->dmg)
                    630:                self->dmg = 1;
                    631: 
                    632:        VectorSet (self->mins, -8, -8, -8);
                    633:        VectorSet (self->maxs, 8, 8, 8);
                    634:        gi.linkentity (self);
                    635: 
                    636:        if (self->spawnflags & 1)
                    637:                target_laser_on (self);
                    638:        else
                    639:                target_laser_off (self);
                    640: }
                    641: 
                    642: void SP_target_laser (edict_t *self)
                    643: {
                    644:        // let everything else get spawned before we start firing
                    645:        self->think = target_laser_start;
                    646:        self->nextthink = level.time + 1;
                    647: }
                    648: 
                    649: //==========================================================
                    650: 
                    651: /*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE
                    652: speed          How many seconds the ramping will take
                    653: message                two letters; starting lightlevel and ending lightlevel
                    654: */
                    655: 
                    656: void target_lightramp_think (edict_t *self)
                    657: {
                    658:        char    style[2];
                    659: 
                    660:        style[0] = 'a' + self->movedir[0] + (level.time - self->timestamp) / FRAMETIME * self->movedir[2];
                    661:        style[1] = 0;
                    662:        gi.configstring (CS_LIGHTS+self->enemy->style, style);
                    663: 
                    664:        if ((level.time - self->timestamp) < self->speed)
                    665:        {
                    666:                self->nextthink = level.time + FRAMETIME;
                    667:        }
                    668:        else if (self->spawnflags & 1)
                    669:        {
                    670:                char    temp;
                    671: 
                    672:                temp = self->movedir[0];
                    673:                self->movedir[0] = self->movedir[1];
                    674:                self->movedir[1] = temp;
                    675:                self->movedir[2] *= -1;
                    676:        }
                    677: }
                    678: 
                    679: void target_lightramp_use (edict_t *self, edict_t *other, edict_t *activator)
                    680: {
                    681:        if (!self->enemy)
                    682:        {
                    683:                edict_t         *e;
                    684: 
                    685:                // check all the targets
                    686:                e = NULL;
                    687:                while (1)
                    688:                {
                    689:                        e = G_Find (e, FOFS(targetname), self->target);
                    690:                        if (!e)
                    691:                                break;
                    692:                        if (strcmp(e->classname, "light") != 0)
                    693:                        {
                    694:                                gi.dprintf("%s at %s ", self->classname, vtos(self->s.origin));
                    695:                                gi.dprintf("target %s (%s at %s) is not a light\n", self->target, e->classname, vtos(e->s.origin));
                    696:                        }
                    697:                        else
                    698:                        {
                    699:                                self->enemy = e;
                    700:                        }
                    701:                }
                    702: 
                    703:                if (!self->enemy)
                    704:                {
                    705:                        gi.dprintf("%s target %s not found at %s\n", self->classname, self->target, vtos(self->s.origin));
                    706:                        G_FreeEdict (self);
                    707:                        return;
                    708:                }
                    709:        }
                    710: 
                    711:        self->timestamp = level.time;
                    712:        target_lightramp_think (self);
                    713: }
                    714: 
                    715: void SP_target_lightramp (edict_t *self)
                    716: {
                    717:        if (!self->message || strlen(self->message) != 2 || self->message[0] < 'a' || self->message[0] > 'z' || self->message[1] < 'a' || self->message[1] > 'z' || self->message[0] == self->message[1])
                    718:        {
                    719:                gi.dprintf("target_lightramp has bad ramp (%s) at %s\n", self->message, vtos(self->s.origin));
                    720:                G_FreeEdict (self);
                    721:                return;
                    722:        }
                    723: 
                    724:        if (deathmatch->value)
                    725:        {
                    726:                G_FreeEdict (self);
                    727:                return;
                    728:        }
                    729: 
                    730:        if (!self->target)
                    731:        {
                    732:                gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
                    733:                G_FreeEdict (self);
                    734:                return;
                    735:        }
                    736: 
                    737:        self->svflags |= SVF_NOCLIENT;
                    738:        self->use = target_lightramp_use;
                    739:        self->think = target_lightramp_think;
                    740: 
                    741:        self->movedir[0] = self->message[0] - 'a';
                    742:        self->movedir[1] = self->message[1] - 'a';
                    743:        self->movedir[2] = (self->movedir[1] - self->movedir[0]) / (self->speed / FRAMETIME);
                    744: }
                    745: 
                    746: //==========================================================
                    747: 
                    748: /*QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8)
                    749: When triggered, this initiates a level-wide earthquake.
                    750: All players and monsters are affected.
                    751: "speed"                severity of the quake (default:200)
                    752: "count"                duration of the quake (default:5)
                    753: */
                    754: 
                    755: void target_earthquake_think (edict_t *self)
                    756: {
                    757:        int             i;
                    758:        edict_t *e;
                    759: 
                    760:        if (self->last_move_time < level.time)
                    761:        {
                    762:                gi.positioned_sound (self->s.origin, self, CHAN_AUTO, self->noise_index, 1.0, ATTN_NONE, 0);
                    763:                self->last_move_time = level.time + 0.5;
                    764:        }
                    765: 
                    766:        for (i=1, e=g_edicts+i; i < globals.num_edicts; i++,e++)
                    767:        {
                    768:                if (!e->inuse)
                    769:                        continue;
                    770:                if (!e->client)
                    771:                        continue;
                    772:                if (!e->groundentity)
                    773:                        continue;
                    774: 
                    775:                e->groundentity = NULL;
                    776:                e->velocity[0] += crandom()* 150;
                    777:                e->velocity[1] += crandom()* 150;
                    778:                e->velocity[2] = self->speed * (100.0 / e->mass);
                    779:        }
                    780: 
                    781:        if (level.time < self->timestamp)
                    782:                self->nextthink = level.time + FRAMETIME;
                    783: }
                    784: 
                    785: void target_earthquake_use (edict_t *self, edict_t *other, edict_t *activator)
                    786: {
                    787:        self->timestamp = level.time + self->count;
                    788:        self->nextthink = level.time + FRAMETIME;
                    789:        self->activator = activator;
                    790:        self->last_move_time = 0;
                    791: }
                    792: 
                    793: void SP_target_earthquake (edict_t *self)
                    794: {
                    795:        if (!self->targetname)
                    796:                gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
                    797: 
                    798:        if (!self->count)
                    799:                self->count = 5;
                    800: 
                    801:        if (!self->speed)
                    802:                self->speed = 200;
                    803: 
                    804:        self->svflags |= SVF_NOCLIENT;
                    805:        self->think = target_earthquake_think;
                    806:        self->use = target_earthquake_use;
                    807: 
                    808:        self->noise_index = gi.soundindex ("world/quake.wav");
                    809: }

unix.superglobalmegacorp.com

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