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