]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/func.qc
Fixed two minor bugs.
[divverent/nexuiz.git] / qcsrc / func.qc
1 void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove;
2 void()  SUB_CalcMoveDone;
3 void() SUB_CalcAngleMoveDone;
4 void() SUB_Null;
5 //void() SUB_UseTargets;
6 void() SUB_Remove;
7
8 void info_null (void)
9 {
10         
11 }
12
13 /*
14 ==================
15 SUB_Null
16
17 Do nothing
18 ==================
19 */
20 void SUB_Null (void)
21 {
22         
23 }
24
25 /*
26 ==================
27 SUB_Remove
28
29 Remove self
30 ==================
31 */
32 void SUB_Remove (void)
33 {
34         remove (self);
35 }
36
37 /*
38 ==================
39 SUB_VanishOrRemove
40
41 Makes ent invisible or removes it if ent.norespawn
42 ==================
43 */
44 void SUB_VanishOrRemove (entity ent)
45 {
46         if (ent.norespawn)
47         {
48                 // remove
49                 remove (ent);
50         }
51         else
52         {
53                 // vanish
54                 ent.effects = EF_NODRAW;
55         }
56 }
57
58 void SUB_SetFade_Think (void)
59 {
60         self.think = SUB_SetFade_Think;
61         self.nextthink = self.fade_time;
62         self.alpha = 1 - (time - self.fade_time) * 0.5;
63         if (self.alpha > 1)
64                 self.alpha = 1;
65         if (self.alpha < 0.01)  // don't let it reach 0, lest it become fully visible again
66                 SUB_VanishOrRemove(self);
67 }
68
69 /*
70 ==================
71 SUB_SetFade
72
73 Fade 'ent' out when time >= 'when'
74 ==================
75 */
76 void SUB_SetFade (entity ent, float when)
77 {
78         if (self.flags & FL_CLIENT) // && self.deadflag != DEAD_NO)
79                 return;
80         ent.alpha = 1;
81         ent.fade_time = when;
82         ent.think = SUB_SetFade_Think;
83         ent.nextthink = when;
84 }
85
86 /*
87 =============
88 SUB_CalcMove
89
90 calculate self.velocity and self.nextthink to reach dest from
91 self.origin traveling at speed
92 ===============
93 */
94 void SUB_CalcMoveDone (void)
95 {
96         // After moving, set origin to exact final destination
97         
98         setorigin (self, self.finaldest);
99         self.velocity = '0 0 0';
100         self.nextthink = -1;
101         if (self.think1)
102                 self.think1 ();
103 }
104
105 void SUB_CalcMove (vector tdest, float tspeed, void() func)
106 {
107         vector  delta;
108         float   traveltime;
109         
110         if (!tspeed)
111                 objerror ("No speed is defined!");
112         
113         self.think1 = func;
114         self.finaldest = tdest;
115         self.think = SUB_CalcMoveDone;
116         
117         if (tdest == self.origin)
118         {
119                 self.velocity = '0 0 0';
120                 self.nextthink = self.ltime + 0.1;
121                 return;
122         }
123         
124         delta = tdest - self.origin;
125         traveltime = vlen (delta) / tspeed;
126         
127         if (traveltime < 0.1)
128         {
129                 self.velocity = '0 0 0';
130                 self.nextthink = self.ltime + 0.1;
131                 return;
132         }
133         
134         self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
135         
136         self.nextthink = self.ltime + traveltime;
137 }
138
139 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
140 {
141         entity  oldself;
142         
143         oldself = self;
144         self = ent;
145         
146         SUB_CalcMove (tdest, tspeed, func);
147         
148         self = oldself;
149 }
150
151 /*
152 =============
153 SUB_CalcAngleMove
154
155 calculate self.avelocity and self.nextthink to reach destangle from
156 self.angles rotating 
157
158 The calling function should make sure self.think is valid
159 ===============
160 */
161 void SUB_CalcAngleMoveDone (void)
162 {
163         // After rotating, set angle to exact final angle
164         self.angles = self.finalangle;
165         self.avelocity = '0 0 0';
166         self.nextthink = -1;
167         if (self.think1)
168                 self.think1 ();
169 }
170
171 void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
172 {
173         vector  delta;
174         float   traveltime;
175         
176         if (!tspeed)
177                 objerror ("No speed is defined!");
178
179         delta = destangle = self.angles;
180         traveltime = vlen (delta) / tspeed;
181         
182         self.avelocity = delta * (1 / traveltime);
183         
184         self.think1 = func;
185         self.finalangle = destangle;
186         
187         self.think = SUB_CalcAngleMoveDone;
188         self.nextthink = self.ltime + traveltime;
189 }
190
191 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeed, void() func)
192 {
193         entity  oldself;
194         
195         oldself = self;
196         self = ent;
197         
198         SUB_CalcAngleMove (destangle, tspeed, func);
199         
200         self = oldself;
201 }
202
203 /*
204 ==================
205 main
206
207 unused but required by the engine
208 ==================
209 */
210 void main (void)
211 {
212         
213 }
214
215 // Sound functions
216
217 /*
218 ==================
219 PointSound
220
221 Play a sound at the given location
222 ==================
223 */
224 void PointSound (vector org, string snd, float vol, float attn)
225 {
226         entity  speaker;
227         
228         speaker = spawn ();
229         setorigin (speaker, org);
230         sound (speaker, CHAN_BODY, snd, vol, attn);
231         remove (speaker);
232 }
233
234 // Misc
235
236 /*
237 ==================
238 traceline_hitcorpse
239
240 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
241 ==================
242 */
243 void traceline_hitcorpse (entity source, vector v1, vector v2, float nomonst, entity forent)
244 {
245         float   oldsolid;
246         
247         oldsolid = source.solid;
248         source.solid = SOLID_BBOX;
249         
250         traceline (v1, v2, nomonst, forent);
251         
252         source.solid = oldsolid;
253 }
254
255 /*
256 ==================
257 findbetterlocation
258
259 Returns a point at least 12 units away from walls
260 (useful for explosion animations, although the blast is performed where it really happened)
261 Ripped from DPMod
262 ==================
263 */
264 vector findbetterlocation (vector org)
265 {
266         vector  loc;
267         
268         traceline (org, org - '12 0 0', TRUE, world);
269         if (trace_fraction < 1)
270         {
271                 loc = trace_endpos;
272                 traceline (loc, loc + '12 0 0', TRUE, world);
273                 if (trace_fraction >= 1)
274                         org = loc + '12 0 0';
275         }
276         
277         traceline (org, org - '-12 0 0', TRUE, world);
278         if (trace_fraction < 1)
279         {
280                 loc = trace_endpos;
281                 traceline (loc, loc + '-12 0 0', TRUE, world);
282                 if (trace_fraction >= 1)
283                         org = loc + '-12 0 0';
284         }
285         
286         traceline (org, org - '0 12 0' , TRUE, world);
287         if (trace_fraction < 1)
288         {
289                 loc = trace_endpos;
290                 traceline (loc, loc + '0 12 0', TRUE, world);
291                 if (trace_fraction >= 1)
292                         org = loc + '0 12 0';
293         }
294         
295         traceline (org, org - '0 -12 0', TRUE, world);
296         if (trace_fraction < 1)
297         {
298                 loc = trace_endpos;
299                 traceline (loc, loc + '0 -12 0', TRUE, world);
300                 if (trace_fraction >= 1)
301                         org = loc + '0 -12 0';
302         }
303         
304         traceline (org, org - '0 0 12' , TRUE, world);
305         if (trace_fraction < 1)
306         {
307                 loc = trace_endpos;
308                 traceline (loc, loc + '0 0 12', TRUE, world);
309                 if (trace_fraction >= 1)
310                         org = loc + '0 0 12';
311         }
312         
313         traceline (org, org - '0 0 -12', TRUE, world);
314         if (trace_fraction < 1)
315         {
316                 loc = trace_endpos;
317                 traceline (loc, loc + '0 0 -12', TRUE, world);
318                 if (trace_fraction >= 1)
319                         org = loc + '0 0 -12';
320         }
321         
322         return org;
323 }
324
325 /*
326 ==================
327 crandom
328
329 Returns a random number between -1.0 and 1.0
330 ==================
331 */
332 float crandom (void)
333 {
334         return 2 * (random () - 0.5);
335 }
336
337 // Violence
338
339 /*
340 ==================
341 ImpactEffect
342
343 Plays an impact effect
344 ==================
345 */
346
347 void ImpactEffect (entity ent, float weapontype)
348 {
349         vector  org2;
350         org2 = findbetterlocation (ent.origin);
351         float b;
352         
353         if (weapontype == IT_ROCKET_LAUNCHER)
354         {
355                 te_explosion (org2);
356                 effect (org2, "models/sprites/dpexplosion1.spr32", 0, 20, 40);
357                 sound (ent, CHAN_BODY, "weapons/rocket_impact.wav", 1, ATTN_NORM);
358         }
359         else if (weapontype == IT_GRENADE_LAUNCHER)
360         {
361                 te_explosion (org2);
362                 effect (org2, "models/sprites/dpexplosion1.spr32", 0, 20, 30);
363                 sound (ent, CHAN_BODY, "weapons/grenade_impact.wav", 1, ATTN_NORM);
364         }
365         else if (weapontype == IT_HAGAR)
366         {
367                 effect (org2, "models/sprites/dpexplosion2.spr32", 0, 20, 30);
368                 b = crandom();
369                 if (b<-0.7)
370                 sound (ent, CHAN_BODY, "weapons/hagexp1.wav", 1, ATTN_NORM);
371                 else if (b<0.4)
372                 sound (ent, CHAN_BODY, "weapons/hagexp2.wav", 1, ATTN_NORM);
373                 else if (b<1)
374                 sound (ent, CHAN_BODY, "weapons/hagexp3.wav", 1, ATTN_NORM);
375         }
376 }
377
378
379 /*
380 ==================
381 Angc used for animations
382 ==================
383 */
384
385
386 float angc (float a1, float a2)
387 {
388         float   a;
389
390         while (a1 > 180)
391                 a1 = a1 - 360;
392         while (a1 < -179)
393                 a1 = a1 + 360;
394
395         while (a2 > 180)
396                 a2 = a2 - 360;
397         while (a2 < -179)
398                 a2 = a2 + 360;
399
400         a = a1 - a2;
401         while (a > 180)
402                 a = a - 360;
403         while (a < -179)
404                 a = a + 360;
405
406         return a;
407 }
408
409
410 /*
411 ================
412 InitTrigger
413 ================
414 */
415
416 void() SetMovedir =
417 {
418         if (self.movedir != '0 0 0')
419                 self.movedir = normalize(self.movedir);
420         else
421         {
422                 if (self.angles == '0 -1 0')
423                         self.movedir = '0 0 1';
424                 else if (self.angles == '0 -2 0')
425                         self.movedir = '0 0 -1';
426                 else
427                 {
428                         makevectors (self.angles);
429                         self.movedir = v_forward;
430                 }
431         }
432
433         self.angles = '0 0 0';
434 };
435
436 void() InitTrigger =
437 {
438 // trigger angles are used for one-way touches.  An angle of 0 is assumed
439 // to mean no restrictions, so use a yaw of 360 instead.
440         if (self.movedir == '0 0 0')
441         if (self.angles != '0 0 0')
442                 SetMovedir ();
443         self.solid = SOLID_TRIGGER;
444         setmodel (self, self.model);    // set size and link into world
445         self.movetype = MOVETYPE_NONE;
446         self.modelindex = 0;
447         self.model = "";
448 };
449
450 void() InitSolidBSPTrigger =
451 {
452 // trigger angles are used for one-way touches.  An angle of 0 is assumed
453 // to mean no restrictions, so use a yaw of 360 instead.
454         if (self.movedir == '0 0 0')
455         if (self.angles != '0 0 0')
456                 SetMovedir ();
457         self.solid = SOLID_BSP;
458         setmodel (self, self.model);    // set size and link into world
459         self.movetype = MOVETYPE_PUSH;
460 //      self.modelindex = 0;
461         self.model = "";
462 };