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