123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810 |
- /*
- Copyright (C) 1997-2001 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "g_local.h"
- /*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
- Fire an origin based temp entity event to the clients.
- "style" type byte
- */
- void Use_Target_Tent (edict_t *ent, edict_t *other, edict_t *activator)
- {
- gi.WriteByte (svc_temp_entity);
- gi.WriteByte (ent->style);
- gi.WritePosition (ent->s.origin);
- gi.multicast (ent->s.origin, MULTICAST_PVS);
- }
- void SP_target_temp_entity (edict_t *ent)
- {
- ent->use = Use_Target_Tent;
- }
- //==========================================================
- //==========================================================
- /*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable
- "noise" wav file to play
- "attenuation"
- -1 = none, send to whole level
- 1 = normal fighting sounds
- 2 = idle sound level
- 3 = ambient sound level
- "volume" 0.0 to 1.0
- Normal sounds play each time the target is used. The reliable flag can be set for crucial voiceovers.
- Looped sounds are always atten 3 / vol 1, and the use function toggles it on/off.
- Multiple identical looping sounds will just increase volume without any speed cost.
- */
- void Use_Target_Speaker (edict_t *ent, edict_t *other, edict_t *activator)
- {
- int chan;
- if (ent->spawnflags & 3)
- { // looping sound toggles
- if (ent->s.sound)
- ent->s.sound = 0; // turn it off
- else
- ent->s.sound = ent->noise_index; // start it
- }
- else
- { // normal sound
- if (ent->spawnflags & 4)
- chan = CHAN_VOICE|CHAN_RELIABLE;
- else
- chan = CHAN_VOICE;
- // use a positioned_sound, because this entity won't normally be
- // sent to any clients because it is invisible
- gi.positioned_sound (ent->s.origin, ent, chan, ent->noise_index, ent->volume, ent->attenuation, 0);
- }
- }
- void SP_target_speaker (edict_t *ent)
- {
- char buffer[MAX_QPATH];
- if(!st.noise)
- {
- gi.dprintf("target_speaker with no noise set at %s\n", vtos(ent->s.origin));
- return;
- }
- if (!strstr (st.noise, ".wav"))
- Com_sprintf (buffer, sizeof(buffer), "%s.wav", st.noise);
- else
- strncpy (buffer, st.noise, sizeof(buffer));
- ent->noise_index = gi.soundindex (buffer);
- if (!ent->volume)
- ent->volume = 1.0;
- if (!ent->attenuation)
- ent->attenuation = 1.0;
- else if (ent->attenuation == -1) // use -1 so 0 defaults to 1
- ent->attenuation = 0;
- // check for prestarted looping sound
- if (ent->spawnflags & 1)
- ent->s.sound = ent->noise_index;
- ent->use = Use_Target_Speaker;
- // must link the entity so we get areas and clusters so
- // the server can determine who to send updates to
- gi.linkentity (ent);
- }
- //==========================================================
- void Use_Target_Help (edict_t *ent, edict_t *other, edict_t *activator)
- {
- if (ent->spawnflags & 1)
- strncpy (game.helpmessage1, ent->message, sizeof(game.helpmessage2)-1);
- else
- strncpy (game.helpmessage2, ent->message, sizeof(game.helpmessage1)-1);
- game.helpchanged++;
- }
- /*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1
- When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars.
- */
- void SP_target_help(edict_t *ent)
- {
- if (deathmatch->value)
- { // auto-remove for deathmatch
- G_FreeEdict (ent);
- return;
- }
- if (!ent->message)
- {
- gi.dprintf ("%s with no message at %s\n", ent->classname, vtos(ent->s.origin));
- G_FreeEdict (ent);
- return;
- }
- ent->use = Use_Target_Help;
- }
- //==========================================================
- /*QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8)
- Counts a secret found.
- These are single use targets.
- */
- void use_target_secret (edict_t *ent, edict_t *other, edict_t *activator)
- {
- gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
- level.found_secrets++;
- G_UseTargets (ent, activator);
- G_FreeEdict (ent);
- }
- void SP_target_secret (edict_t *ent)
- {
- if (deathmatch->value)
- { // auto-remove for deathmatch
- G_FreeEdict (ent);
- return;
- }
- ent->use = use_target_secret;
- if (!st.noise)
- st.noise = "misc/secret.wav";
- ent->noise_index = gi.soundindex (st.noise);
- ent->svflags = SVF_NOCLIENT;
- level.total_secrets++;
- // map bug hack
- if (!Q_stricmp(level.mapname, "mine3") && ent->s.origin[0] == 280 && ent->s.origin[1] == -2048 && ent->s.origin[2] == -624)
- ent->message = "You have found a secret area.";
- }
- //==========================================================
- /*QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8)
- Counts a goal completed.
- These are single use targets.
- */
- void use_target_goal (edict_t *ent, edict_t *other, edict_t *activator)
- {
- gi.sound (ent, CHAN_VOICE, ent->noise_index, 1, ATTN_NORM, 0);
- level.found_goals++;
- if (level.found_goals == level.total_goals)
- gi.configstring (CS_CDTRACK, "0");
- G_UseTargets (ent, activator);
- G_FreeEdict (ent);
- }
- void SP_target_goal (edict_t *ent)
- {
- if (deathmatch->value)
- { // auto-remove for deathmatch
- G_FreeEdict (ent);
- return;
- }
- ent->use = use_target_goal;
- if (!st.noise)
- st.noise = "misc/secret.wav";
- ent->noise_index = gi.soundindex (st.noise);
- ent->svflags = SVF_NOCLIENT;
- level.total_goals++;
- }
- //==========================================================
- /*QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8)
- Spawns an explosion temporary entity when used.
- "delay" wait this long before going off
- "dmg" how much radius damage should be done, defaults to 0
- */
- void target_explosion_explode (edict_t *self)
- {
- float save;
- gi.WriteByte (svc_temp_entity);
- gi.WriteByte (TE_EXPLOSION1);
- gi.WritePosition (self->s.origin);
- gi.multicast (self->s.origin, MULTICAST_PHS);
- T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
- save = self->delay;
- self->delay = 0;
- G_UseTargets (self, self->activator);
- self->delay = save;
- }
- void use_target_explosion (edict_t *self, edict_t *other, edict_t *activator)
- {
- self->activator = activator;
- if (!self->delay)
- {
- target_explosion_explode (self);
- return;
- }
- self->think = target_explosion_explode;
- self->nextthink = level.time + self->delay;
- }
- void SP_target_explosion (edict_t *ent)
- {
- ent->use = use_target_explosion;
- ent->svflags = SVF_NOCLIENT;
- }
- //==========================================================
- /*QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8)
- Changes level to "map" when fired
- */
- void use_target_changelevel (edict_t *self, edict_t *other, edict_t *activator)
- {
- if (level.intermissiontime)
- return; // already activated
- if (!deathmatch->value && !coop->value)
- {
- if (g_edicts[1].health <= 0)
- return;
- }
- // if noexit, do a ton of damage to other
- if (deathmatch->value && !( (int)dmflags->value & DF_ALLOW_EXIT) && other != world)
- {
- T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 10 * other->max_health, 1000, 0, MOD_EXIT);
- return;
- }
- // if multiplayer, let everyone know who hit the exit
- if (deathmatch->value)
- {
- if (activator && activator->client)
- gi.bprintf (PRINT_HIGH, "%s exited the level.\n", activator->client->pers.netname);
- }
- // if going to a new unit, clear cross triggers
- if (strstr(self->map, "*"))
- game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK);
- BeginIntermission (self);
- }
- void SP_target_changelevel (edict_t *ent)
- {
- if (!ent->map)
- {
- gi.dprintf("target_changelevel with no map at %s\n", vtos(ent->s.origin));
- G_FreeEdict (ent);
- return;
- }
- // ugly hack because *SOMEBODY* screwed up their map
- if((Q_stricmp(level.mapname, "fact1") == 0) && (Q_stricmp(ent->map, "fact3") == 0))
- ent->map = "fact3$secret1";
- ent->use = use_target_changelevel;
- ent->svflags = SVF_NOCLIENT;
- }
- //==========================================================
- /*QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8)
- Creates a particle splash effect when used.
- Set "sounds" to one of the following:
- 1) sparks
- 2) blue water
- 3) brown water
- 4) slime
- 5) lava
- 6) blood
- "count" how many pixels in the splash
- "dmg" if set, does a radius damage at this location when it splashes
- useful for lava/sparks
- */
- void use_target_splash (edict_t *self, edict_t *other, edict_t *activator)
- {
- gi.WriteByte (svc_temp_entity);
- gi.WriteByte (TE_SPLASH);
- gi.WriteByte (self->count);
- gi.WritePosition (self->s.origin);
- gi.WriteDir (self->movedir);
- gi.WriteByte (self->sounds);
- gi.multicast (self->s.origin, MULTICAST_PVS);
- if (self->dmg)
- T_RadiusDamage (self, activator, self->dmg, NULL, self->dmg+40, MOD_SPLASH);
- }
- void SP_target_splash (edict_t *self)
- {
- self->use = use_target_splash;
- G_SetMovedir (self->s.angles, self->movedir);
- if (!self->count)
- self->count = 32;
- self->svflags = SVF_NOCLIENT;
- }
- //==========================================================
- /*QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8)
- Set target to the type of entity you want spawned.
- Useful for spawning monsters and gibs in the factory levels.
- For monsters:
- Set direction to the facing you want it to have.
- For gibs:
- Set direction if you want it moving and
- speed how fast it should be moving otherwise it
- will just be dropped
- */
- void ED_CallSpawn (edict_t *ent);
- void use_target_spawner (edict_t *self, edict_t *other, edict_t *activator)
- {
- edict_t *ent;
- ent = G_Spawn();
- ent->classname = self->target;
- VectorCopy (self->s.origin, ent->s.origin);
- VectorCopy (self->s.angles, ent->s.angles);
- ED_CallSpawn (ent);
- gi.unlinkentity (ent);
- KillBox (ent);
- gi.linkentity (ent);
- if (self->speed)
- VectorCopy (self->movedir, ent->velocity);
- }
- void SP_target_spawner (edict_t *self)
- {
- self->use = use_target_spawner;
- self->svflags = SVF_NOCLIENT;
- if (self->speed)
- {
- G_SetMovedir (self->s.angles, self->movedir);
- VectorScale (self->movedir, self->speed, self->movedir);
- }
- }
- //==========================================================
- /*QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS
- Fires a blaster bolt in the set direction when triggered.
- dmg default is 15
- speed default is 1000
- */
- void use_target_blaster (edict_t *self, edict_t *other, edict_t *activator)
- {
- int effect;
- if (self->spawnflags & 2)
- effect = 0;
- else if (self->spawnflags & 1)
- effect = EF_HYPERBLASTER;
- else
- effect = EF_BLASTER;
- fire_blaster (self, self->s.origin, self->movedir, self->dmg, self->speed, EF_BLASTER, MOD_TARGET_BLASTER);
- gi.sound (self, CHAN_VOICE, self->noise_index, 1, ATTN_NORM, 0);
- }
- void SP_target_blaster (edict_t *self)
- {
- self->use = use_target_blaster;
- G_SetMovedir (self->s.angles, self->movedir);
- self->noise_index = gi.soundindex ("weapons/laser2.wav");
- if (!self->dmg)
- self->dmg = 15;
- if (!self->speed)
- self->speed = 1000;
- self->svflags = SVF_NOCLIENT;
- }
- //==========================================================
- /*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
- 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.
- */
- void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator)
- {
- game.serverflags |= self->spawnflags;
- G_FreeEdict (self);
- }
- void SP_target_crosslevel_trigger (edict_t *self)
- {
- self->svflags = SVF_NOCLIENT;
- self->use = trigger_crosslevel_trigger_use;
- }
- /*QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8
- Triggered by a trigger_crosslevel elsewhere within a unit. If multiple triggers are checked, all must be true. Delay, target and
- killtarget also work.
- "delay" delay before using targets if the trigger has been activated (default 1)
- */
- void target_crosslevel_target_think (edict_t *self)
- {
- if (self->spawnflags == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self->spawnflags))
- {
- G_UseTargets (self, self);
- G_FreeEdict (self);
- }
- }
- void SP_target_crosslevel_target (edict_t *self)
- {
- if (! self->delay)
- self->delay = 1;
- self->svflags = SVF_NOCLIENT;
- self->think = target_crosslevel_target_think;
- self->nextthink = level.time + self->delay;
- }
- //==========================================================
- /*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT
- When triggered, fires a laser. You can either set a target
- or a direction.
- */
- void target_laser_think (edict_t *self)
- {
- edict_t *ignore;
- vec3_t start;
- vec3_t end;
- trace_t tr;
- vec3_t point;
- vec3_t last_movedir;
- int count;
- if (self->spawnflags & 0x80000000)
- count = 8;
- else
- count = 4;
- if (self->enemy)
- {
- VectorCopy (self->movedir, last_movedir);
- VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
- VectorSubtract (point, self->s.origin, self->movedir);
- VectorNormalize (self->movedir);
- if (!VectorCompare(self->movedir, last_movedir))
- self->spawnflags |= 0x80000000;
- }
- ignore = self;
- VectorCopy (self->s.origin, start);
- VectorMA (start, 2048, self->movedir, end);
- while(1)
- {
- tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
- if (!tr.ent)
- break;
- // hurt it if we can
- if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER))
- T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER);
- // if we hit something that's not a monster or player or is immune to lasers, we're done
- if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
- {
- if (self->spawnflags & 0x80000000)
- {
- self->spawnflags &= ~0x80000000;
- gi.WriteByte (svc_temp_entity);
- gi.WriteByte (TE_LASER_SPARKS);
- gi.WriteByte (count);
- gi.WritePosition (tr.endpos);
- gi.WriteDir (tr.plane.normal);
- gi.WriteByte (self->s.skinnum);
- gi.multicast (tr.endpos, MULTICAST_PVS);
- }
- break;
- }
- ignore = tr.ent;
- VectorCopy (tr.endpos, start);
- }
- VectorCopy (tr.endpos, self->s.old_origin);
- self->nextthink = level.time + FRAMETIME;
- }
- void target_laser_on (edict_t *self)
- {
- if (!self->activator)
- self->activator = self;
- self->spawnflags |= 0x80000001;
- self->svflags &= ~SVF_NOCLIENT;
- target_laser_think (self);
- }
- void target_laser_off (edict_t *self)
- {
- self->spawnflags &= ~1;
- self->svflags |= SVF_NOCLIENT;
- self->nextthink = 0;
- }
- void target_laser_use (edict_t *self, edict_t *other, edict_t *activator)
- {
- self->activator = activator;
- if (self->spawnflags & 1)
- target_laser_off (self);
- else
- target_laser_on (self);
- }
- void target_laser_start (edict_t *self)
- {
- edict_t *ent;
- self->movetype = MOVETYPE_NONE;
- self->solid = SOLID_NOT;
- self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT;
- self->s.modelindex = 1; // must be non-zero
- // set the beam diameter
- if (self->spawnflags & 64)
- self->s.frame = 16;
- else
- self->s.frame = 4;
- // set the color
- if (self->spawnflags & 2)
- self->s.skinnum = 0xf2f2f0f0;
- else if (self->spawnflags & 4)
- self->s.skinnum = 0xd0d1d2d3;
- else if (self->spawnflags & 8)
- self->s.skinnum = 0xf3f3f1f1;
- else if (self->spawnflags & 16)
- self->s.skinnum = 0xdcdddedf;
- else if (self->spawnflags & 32)
- self->s.skinnum = 0xe0e1e2e3;
- if (!self->enemy)
- {
- if (self->target)
- {
- ent = G_Find (NULL, FOFS(targetname), self->target);
- if (!ent)
- gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
- self->enemy = ent;
- }
- else
- {
- G_SetMovedir (self->s.angles, self->movedir);
- }
- }
- self->use = target_laser_use;
- self->think = target_laser_think;
- if (!self->dmg)
- self->dmg = 1;
- VectorSet (self->mins, -8, -8, -8);
- VectorSet (self->maxs, 8, 8, 8);
- gi.linkentity (self);
- if (self->spawnflags & 1)
- target_laser_on (self);
- else
- target_laser_off (self);
- }
- void SP_target_laser (edict_t *self)
- {
- // let everything else get spawned before we start firing
- self->think = target_laser_start;
- self->nextthink = level.time + 1;
- }
- //==========================================================
- /*QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE
- speed How many seconds the ramping will take
- message two letters; starting lightlevel and ending lightlevel
- */
- void target_lightramp_think (edict_t *self)
- {
- char style[2];
- style[0] = 'a' + self->movedir[0] + (level.time - self->timestamp) / FRAMETIME * self->movedir[2];
- style[1] = 0;
- gi.configstring (CS_LIGHTS+self->enemy->style, style);
- if ((level.time - self->timestamp) < self->speed)
- {
- self->nextthink = level.time + FRAMETIME;
- }
- else if (self->spawnflags & 1)
- {
- char temp;
- temp = self->movedir[0];
- self->movedir[0] = self->movedir[1];
- self->movedir[1] = temp;
- self->movedir[2] *= -1;
- }
- }
- void target_lightramp_use (edict_t *self, edict_t *other, edict_t *activator)
- {
- if (!self->enemy)
- {
- edict_t *e;
- // check all the targets
- e = NULL;
- while (1)
- {
- e = G_Find (e, FOFS(targetname), self->target);
- if (!e)
- break;
- if (strcmp(e->classname, "light") != 0)
- {
- gi.dprintf("%s at %s ", self->classname, vtos(self->s.origin));
- gi.dprintf("target %s (%s at %s) is not a light\n", self->target, e->classname, vtos(e->s.origin));
- }
- else
- {
- self->enemy = e;
- }
- }
- if (!self->enemy)
- {
- gi.dprintf("%s target %s not found at %s\n", self->classname, self->target, vtos(self->s.origin));
- G_FreeEdict (self);
- return;
- }
- }
- self->timestamp = level.time;
- target_lightramp_think (self);
- }
- void SP_target_lightramp (edict_t *self)
- {
- 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])
- {
- gi.dprintf("target_lightramp has bad ramp (%s) at %s\n", self->message, vtos(self->s.origin));
- G_FreeEdict (self);
- return;
- }
- if (deathmatch->value)
- {
- G_FreeEdict (self);
- return;
- }
- if (!self->target)
- {
- gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
- G_FreeEdict (self);
- return;
- }
- self->svflags |= SVF_NOCLIENT;
- self->use = target_lightramp_use;
- self->think = target_lightramp_think;
- self->movedir[0] = self->message[0] - 'a';
- self->movedir[1] = self->message[1] - 'a';
- self->movedir[2] = (self->movedir[1] - self->movedir[0]) / (self->speed / FRAMETIME);
- }
- //==========================================================
- /*QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8)
- When triggered, this initiates a level-wide earthquake.
- All players and monsters are affected.
- "speed" severity of the quake (default:200)
- "count" duration of the quake (default:5)
- */
- void target_earthquake_think (edict_t *self)
- {
- int i;
- edict_t *e;
- if (self->last_move_time < level.time)
- {
- gi.positioned_sound (self->s.origin, self, CHAN_AUTO, self->noise_index, 1.0, ATTN_NONE, 0);
- self->last_move_time = level.time + 0.5;
- }
- for (i=1, e=g_edicts+i; i < globals.num_edicts; i++,e++)
- {
- if (!e->inuse)
- continue;
- if (!e->client)
- continue;
- if (!e->groundentity)
- continue;
- e->groundentity = NULL;
- e->velocity[0] += crandom()* 150;
- e->velocity[1] += crandom()* 150;
- e->velocity[2] = self->speed * (100.0 / e->mass);
- }
- if (level.time < self->timestamp)
- self->nextthink = level.time + FRAMETIME;
- }
- void target_earthquake_use (edict_t *self, edict_t *other, edict_t *activator)
- {
- self->timestamp = level.time + self->count;
- self->nextthink = level.time + FRAMETIME;
- self->activator = activator;
- self->last_move_time = 0;
- }
- void SP_target_earthquake (edict_t *self)
- {
- if (!self->targetname)
- gi.dprintf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
- if (!self->count)
- self->count = 5;
- if (!self->speed)
- self->speed = 200;
- self->svflags |= SVF_NOCLIENT;
- self->think = target_earthquake_think;
- self->use = target_earthquake_use;
- self->noise_index = gi.soundindex ("world/quake.wav");
- }
|