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