]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/gamec/g_triggers.c
Updating
[divverent/nexuiz.git] / qcsrc / gamec / g_triggers.c
1
2 void() SUB_UseTargets;
3
4 void() DelayThink =
5 {
6         activator = self.enemy;
7         SUB_UseTargets ();
8         remove(self);
9 };
10
11 /*
12 ==============================
13 SUB_UseTargets
14
15 the global "activator" should be set to the entity that initiated the firing.
16
17 If self.delay is set, a DelayedUse entity will be created that will actually
18 do the SUB_UseTargets after that many seconds have passed.
19
20 Centerprints any self.message to the activator.
21
22 Removes all entities with a targetname that match self.killtarget,
23 and removes them, so some events can remove other triggers.
24
25 Search for (string)targetname in all entities that
26 match (string)self.target and call their .use function
27
28 ==============================
29 */
30 void() SUB_UseTargets =
31 {
32         local entity t, stemp, otemp, act;
33
34 //
35 // check for a delay
36 //
37         if (self.delay)
38         {
39         // create a temp object to fire at a later time
40                 t = spawn();
41                 t.classname = "DelayedUse";
42                 t.nextthink = time + self.delay;
43                 t.think = DelayThink;
44                 t.enemy = activator;
45                 t.message = self.message;
46                 t.killtarget = self.killtarget;
47                 t.target = self.target;
48                 return;
49         }
50         
51         
52 //
53 // print the message
54 //
55         if (activator.classname == "player" && self.message != "")
56         {
57                 centerprint (activator, self.message);
58                 if (!self.noise)
59                         sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
60         }
61
62 //
63 // kill the killtagets
64 //
65         if (self.killtarget)
66         {
67                 t = world;
68                 do
69                 {
70                         t = find (t, targetname, self.killtarget);
71                         if (!t)
72                                 return;
73                         remove (t);
74                 } while ( 1 );
75         }
76         
77 //
78 // fire targets
79 //
80         if (self.target)
81         {
82                 act = activator;
83                 t = world;
84                 do
85                 {
86                         t = find (t, targetname, self.target);
87                         if (!t)
88                         {
89                                 return;
90                         }
91                         stemp = self;
92                         otemp = other;
93                         self = t;
94                         other = stemp;
95                         if (self.use != SUB_Null)
96                         {
97                                 if (self.use)
98                                         self.use ();
99                         }
100                         self = stemp;
101                         other = otemp;
102                         activator = act;
103                 } while ( 1 );
104         }
105         
106
107 };
108
109 entity stemp, otemp, s, old;
110
111
112 void() trigger_reactivate =
113 {
114         self.solid = SOLID_TRIGGER;
115 };
116
117 //=============================================================================
118
119 float   SPAWNFLAG_NOMESSAGE = 1;
120 float   SPAWNFLAG_NOTOUCH = 1;
121
122 // the wait time has passed, so set back up for another activation
123 void() multi_wait =
124 {
125         if (self.max_health)
126         {
127                 self.health = self.max_health;
128                 self.takedamage = DAMAGE_YES;
129                 self.solid = SOLID_BBOX;
130         }
131 };
132
133
134 // the trigger was just touched/killed/used
135 // self.enemy should be set to the activator so it can be held through a delay
136 // so wait for the delay time before firing
137 void() multi_trigger =
138 {
139         if (self.nextthink > time)
140         {
141                 return;         // allready been triggered
142         }
143
144         if (self.classname == "trigger_secret")
145         {
146                 if (self.enemy.classname != "player")
147                         return;
148                 found_secrets = found_secrets + 1;
149                 WriteByte (MSG_ALL, SVC_FOUNDSECRET);
150         }
151
152         if (self.noise)
153                 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
154
155 // don't trigger again until reset
156         self.takedamage = DAMAGE_NO;
157
158         activator = self.enemy;
159         
160         SUB_UseTargets();
161
162         if (self.wait > 0)      
163         {
164                 self.think = multi_wait;
165                 self.nextthink = time + self.wait;
166         }
167         else
168         {       // we can't just remove (self) here, because this is a touch function
169                 // called wheil C code is looping through area links...
170                 self.touch = SUB_Null;
171                 self.nextthink = time + 0.1;
172                 self.think = SUB_Remove;
173         }
174 };
175
176 void() multi_use =
177 {
178         self.enemy = activator;
179         multi_trigger();
180 };
181
182 void() multi_touch =
183 {
184         if (other.classname != "player")
185                 return;
186         
187 // if the trigger has an angles field, check player's facing direction
188         if (self.movedir != '0 0 0')
189         {
190                 makevectors (other.angles);
191                 if (v_forward * self.movedir < 0)
192                         return;         // not facing the right way
193         }
194         
195         self.enemy = other;
196         multi_trigger ();
197 };
198
199 void multi_eventdamage (vector hitloc, float damage, entity inflictor, entity attacker, float deathtype)
200 {
201         if (!self.takedamage)
202                 return;
203         self.health = self.health - damage;
204         if (self.health <= 0)
205         {
206                 self.enemy = attacker;
207                 multi_trigger();
208         }
209 }
210
211 /*QUAKED trigger_multiple (.5 .5 .5) ? notouch
212 Variable sized repeatable trigger.  Must be targeted at one or more entities.  If "health" is set, the trigger must be killed to activate each time.
213 If "delay" is set, the trigger waits some time after activating before firing.
214 "wait" : Seconds between triggerings. (.2 default)
215 If notouch is set, the trigger is only fired by other entities, not by touching.
216 NOTOUCH has been obsoleted by trigger_relay!
217 sounds
218 1)      secret
219 2)      beep beep
220 3)      large switch
221 4)
222 set "message" to text string
223 */
224 void() trigger_multiple =
225 {
226         if (self.sounds == 1)
227         {
228                 precache_sound ("misc/secret.wav");
229                 self.noise = "misc/secret.wav";
230         }
231         else if (self.sounds == 2)
232         {
233                 precache_sound ("misc/talk.wav");
234                 self.noise = "misc/talk.wav";
235         }
236         else if (self.sounds == 3)
237         {
238                 precache_sound ("misc/trigger1.wav");
239                 self.noise = "misc/trigger1.wav";
240         }
241         
242         if (!self.wait)
243                 self.wait = 0.2;
244         self.use = multi_use;
245
246         InitTrigger ();
247
248         if (self.health)
249         {
250                 if (self.spawnflags & SPAWNFLAG_NOTOUCH)
251                         objerror ("health and notouch don't make sense\n");
252                 self.max_health = self.health;
253                 self.event_damage = multi_eventdamage;
254                 self.takedamage = DAMAGE_YES;
255                 self.solid = SOLID_BBOX;
256                 setorigin (self, self.origin);  // make sure it links into the world
257         }
258         else
259         {
260                 if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
261                 {
262                         self.touch = multi_touch;
263                 }
264         }
265 };
266
267
268 /*QUAKED trigger_once (.5 .5 .5) ? notouch
269 Variable sized trigger. Triggers once, then removes itself.  You must set the key "target" to the name of another object in the level that has a matching
270 "targetname".  If "health" is set, the trigger must be killed to activate.
271 If notouch is set, the trigger is only fired by other entities, not by touching.
272 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
273 if "angle" is set, the trigger will only fire when someone is facing the direction of the angle.  Use "360" for an angle of 0.
274 sounds
275 1)      secret
276 2)      beep beep
277 3)      large switch
278 4)
279 set "message" to text string
280 */
281 void() trigger_once =
282 {
283         self.wait = -1;
284         trigger_multiple();
285 };
286
287 //=============================================================================
288
289 /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
290 This fixed size trigger cannot be touched, it can only be fired by other events.  It can contain killtargets, targets, delays, and messages.
291 */
292 void() trigger_relay =
293 {
294         self.use = SUB_UseTargets;
295 };
296
297
298 //=============================================================================
299
300
301 void() counter_use =
302 {
303         local string junk;
304
305         self.count = self.count - 1;
306         if (self.count < 0)
307                 return;
308         
309         if (self.count != 0)
310         {
311                 if (activator.classname == "player"
312                 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
313                 {
314                         if (self.count >= 4)
315                                 centerprint (activator, "There are more to go...");
316                         else if (self.count == 3)
317                                 centerprint (activator, "Only 3 more to go...");
318                         else if (self.count == 2)
319                                 centerprint (activator, "Only 2 more to go...");
320                         else
321                                 centerprint (activator, "Only 1 more to go...");
322                 }
323                 return;
324         }
325         
326         if (activator.classname == "player"
327         && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
328                 centerprint(activator, "Sequence completed!");
329         self.enemy = activator;
330         multi_trigger ();
331 };
332
333 /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
334 Acts as an intermediary for an action that takes multiple inputs.
335
336 If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
337
338 After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
339 */
340 void() trigger_counter =
341 {
342         self.wait = -1;
343         if (!self.count)
344                 self.count = 2;
345
346         self.use = counter_use;
347 };
348
349 void() hurt_on =
350 {
351         self.solid = SOLID_TRIGGER;
352         self.nextthink = -1;
353 };
354
355 void() hurt_touch =
356 {
357         if (other.takedamage)
358         {
359                 self.solid = SOLID_NOT;
360                 Damage (other, self, self, self.dmg, 1, '0 0 0', '0 0 0');
361                 self.think = hurt_on;
362                 self.nextthink = time + 1;
363         }
364
365         return;
366 };
367
368 /*QUAKED trigger_hurt (.5 .5 .5) ?
369 Any object touching this will be hurt
370 set dmg to damage amount
371 defalt dmg = 5
372 */
373 void() trigger_hurt =
374 {
375         InitTrigger ();
376         self.touch = hurt_touch;
377         if (!self.dmg)
378                 self.dmg = 5;
379 };
380
381 //void() target_speaker_use = {sound(self, CHAN_VOICE, self.noise, 1, 1);}
382 //void() target_speaker = {self.use = target_speaker_use;}
383
384 void() target_speaker =
385 {
386 if(self.noise) {
387  precache_sound (self.noise);
388  ambientsound (self.origin, self.noise, 1, ATTN_STATIC);
389 }
390 //remove(self);
391 };
392