]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/g_subs.qc
fix SUB_Friction to only apply when onground
[divverent/nexuiz.git] / data / qcsrc / server / g_subs.qc
1 void SUB_Null() {};
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 spawnfunc_info_null (void)
10 {
11         remove(self);
12         // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
13 }
14
15 /*
16 ==================
17 SUB_Remove
18
19 Remove self
20 ==================
21 */
22 void SUB_Remove (void)
23 {
24         remove (self);
25 }
26
27 /*
28 ==================
29 SUB_Friction
30
31 Applies some friction to self
32 ==================
33 */
34 .float friction;
35 void SUB_Friction (void)
36 {
37         self.nextthink = time;
38         if(self.flags & FL_ONGROUND)
39                 self.velocity = self.velocity * (1 - frametime * self.friction);
40 }
41
42 /*
43 ==================
44 SUB_VanishOrRemove
45
46 Makes client invisible or removes non-client
47 ==================
48 */
49 void SUB_VanishOrRemove (entity ent)
50 {
51         if (ent.flags & FL_CLIENT)
52         {
53                 // vanish
54                 ent.model = "";
55                 ent.effects = 0;
56                 ent.glow_size = 0;
57                 ent.pflags = 0;
58         }
59         else
60         {
61                 // remove
62                 remove (ent);
63         }
64 }
65
66 void SUB_SetFade_Think (void)
67 {
68         self.think = SUB_SetFade_Think;
69         self.nextthink = self.fade_time;
70         self.alpha = 1 - (time - self.fade_time) * self.fade_rate;
71         if (self.alpha < 0.01)
72                 SUB_VanishOrRemove(self);
73         self.alpha = bound(0.01, self.alpha, 1);
74 }
75
76 /*
77 ==================
78 SUB_SetFade
79
80 Fade 'ent' out when time >= 'when'
81 ==================
82 */
83 void SUB_SetFade (entity ent, float when, float fadetime)
84 {
85         //if (ent.flags & FL_CLIENT) // && ent.deadflag != DEAD_NO)
86         //      return;
87         //ent.alpha = 1;
88         ent.fade_rate = 1/fadetime;
89         ent.fade_time = when;
90         ent.think = SUB_SetFade_Think;
91         ent.nextthink = when;
92 }
93
94 /*
95 =============
96 SUB_CalcMove
97
98 calculate self.velocity and self.nextthink to reach dest from
99 self.origin traveling at speed
100 ===============
101 */
102 void SUB_CalcMoveDone (void)
103 {
104         // After moving, set origin to exact final destination
105
106         setorigin (self, self.finaldest);
107         self.velocity = '0 0 0';
108         self.nextthink = -1;
109         if (self.think1)
110                 self.think1 ();
111 }
112
113 void SUB_CalcMove (vector tdest, float tspeed, void() func)
114 {
115         vector  delta;
116         float   traveltime;
117
118         if (!tspeed)
119                 objerror ("No speed is defined!");
120
121         self.think1 = func;
122         self.finaldest = tdest;
123         self.think = SUB_CalcMoveDone;
124
125         if (tdest == self.origin)
126         {
127                 self.velocity = '0 0 0';
128                 self.nextthink = self.ltime + 0.1;
129                 return;
130         }
131
132         delta = tdest - self.origin;
133         traveltime = vlen (delta) / tspeed;
134
135         if (traveltime < 0.1)
136         {
137                 self.velocity = '0 0 0';
138                 self.nextthink = self.ltime + 0.1;
139                 return;
140         }
141
142         self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
143
144         self.nextthink = self.ltime + traveltime;
145 }
146
147 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
148 {
149         entity  oldself;
150
151         oldself = self;
152         self = ent;
153
154         SUB_CalcMove (tdest, tspeed, func);
155
156         self = oldself;
157 }
158
159 /*
160 =============
161 SUB_CalcAngleMove
162
163 calculate self.avelocity and self.nextthink to reach destangle from
164 self.angles rotating
165
166 The calling function should make sure self.think is valid
167 ===============
168 */
169 void SUB_CalcAngleMoveDone (void)
170 {
171         // After rotating, set angle to exact final angle
172         self.angles = self.finalangle;
173         self.avelocity = '0 0 0';
174         self.nextthink = -1;
175         if (self.think1)
176                 self.think1 ();
177 }
178
179 void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
180 {
181         vector  delta;
182         float   traveltime;
183
184         if (!tspeed)
185                 objerror ("No speed is defined!");
186
187         delta = destangle - self.angles;
188         traveltime = vlen (delta) / tspeed;
189
190         self.avelocity = delta * (1 / traveltime);
191
192         self.think1 = func;
193         self.finalangle = destangle;
194
195         self.think = SUB_CalcAngleMoveDone;
196         self.nextthink = self.ltime + traveltime;
197 }
198
199 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeed, void() func)
200 {
201         entity  oldself;
202
203         oldself = self;
204         self = ent;
205
206         SUB_CalcAngleMove (destangle, tspeed, func);
207
208         self = oldself;
209 }
210
211 /*
212 ==================
213 main
214
215 unused but required by the engine
216 ==================
217 */
218 void main (void)
219 {
220
221 }
222
223 // Misc
224
225 /*
226 ==================
227 traceline_antilag
228
229 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
230 Additionally it moves players back into the past before the trace and restores them afterward.
231 ==================
232 */
233 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
234 {
235         local entity player;
236         local float oldsolid;
237
238         // check whether antilagged traces are enabled
239         if (lag < 0.001)
240                 lag = 0;
241         if (clienttype(forent) != CLIENTTYPE_REAL)
242                 lag = 0; // only antilag for clients
243
244         // change shooter to SOLID_BBOX so the shot can hit corpses
245         oldsolid = source.solid;
246         source.solid = SOLID_BBOX;
247
248         if (lag)
249         {
250                 // take players back into the past
251                 player = player_list;
252                 while (player)
253                 {
254                         antilag_takeback(player, time - lag);
255                         player = player.nextplayer;
256                 }
257         }
258
259         // do the trace
260         traceline (v1, v2, nomonst, forent);
261
262         // restore players to current positions
263         if (lag)
264         {
265                 player = player_list;
266                 while (player)
267                 {
268                         antilag_restore(player);
269                         player = player.nextplayer;
270                 }
271         }
272
273         // restore shooter solid type
274         source.solid = oldsolid;
275 }
276 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
277 {
278         if (cvar("g_antilag") != 2)
279                 lag = 0;
280         traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
281 }
282
283 /*
284 ==================
285 findbetterlocation
286
287 Returns a point at least 12 units away from walls
288 (useful for explosion animations, although the blast is performed where it really happened)
289 Ripped from DPMod
290 ==================
291 */
292 vector findbetterlocation (vector org, float mindist)
293 {
294         vector  loc;
295         vector vec;
296         float c;
297
298         vec = mindist * '1 0 0';
299         c = 0;
300         while (c < 6)
301         {
302                 traceline (org, org + vec, TRUE, world);
303                 vec = vec * -1;
304                 if (trace_fraction < 1)
305                 {
306                         loc = trace_endpos;
307                         traceline (loc, loc + vec, TRUE, world);
308                         if (trace_fraction >= 1)
309                                 org = loc + vec;
310                 }
311                 if (c & 1)
312                 {
313                         vec_z = vec_y;
314                         vec_y = vec_x;
315                         vec_x = vec_z;
316                 }
317                 c = c + 1;
318         }
319
320         return org;
321 }
322
323 /*
324 ==================
325 crandom
326
327 Returns a random number between -1.0 and 1.0
328 ==================
329 */
330 float crandom (void)
331 {
332         return 2 * (random () - 0.5);
333 }
334
335 /*
336 ==================
337 Angc used for animations
338 ==================
339 */
340
341
342 float angc (float a1, float a2)
343 {
344         float   a;
345
346         while (a1 > 180)
347                 a1 = a1 - 360;
348         while (a1 < -179)
349                 a1 = a1 + 360;
350
351         while (a2 > 180)
352                 a2 = a2 - 360;
353         while (a2 < -179)
354                 a2 = a2 + 360;
355
356         a = a1 - a2;
357         while (a > 180)
358                 a = a - 360;
359         while (a < -179)
360                 a = a + 360;
361
362         return a;
363 }
364
365 .string lodtarget1;
366 .string lodtarget2;
367 .string lodmodel1;
368 .string lodmodel2;
369 .float lodmodelindex0;
370 .float lodmodelindex1;
371 .float lodmodelindex2;
372 .float loddistance1;
373 .float loddistance2;
374
375 float LOD_customize()
376 {
377         float d;
378
379         // TODO csqc network this so it only gets sent once
380         d = vlen(self.origin - other.origin);
381         if(d < self.loddistance1)
382                 self.modelindex = self.lodmodelindex0;
383         else if(!self.lodmodelindex2 || d < self.loddistance2)
384                 self.modelindex = self.lodmodelindex1;
385         else
386                 self.modelindex = self.lodmodelindex2;
387
388         return TRUE;
389 }
390
391 void LOD_uncustomize()
392 {
393         self.modelindex = self.lodmodelindex0;
394 }
395
396 void LODmodel_attach()
397 {
398         entity e;
399
400         if(!self.loddistance1)
401                 self.loddistance1 = 1000;
402         if(!self.loddistance2)
403                 self.loddistance2 = 2000;
404         self.lodmodelindex0 = self.modelindex;
405
406         if(self.lodtarget1 != "")
407         {
408                 e = find(world, targetname, self.lodtarget1);
409                 if(e)
410                 {
411                         self.lodmodel1 = e.model;
412                         remove(e);
413                 }
414         }
415         if(self.lodtarget2 != "")
416         {
417                 e = find(world, targetname, self.lodtarget2);
418                 if(e)
419                 {
420                         self.lodmodel2 = e.model;
421                         remove(e);
422                 }
423         }
424
425         if(self.lodmodel1 != "")
426         {
427                 vector mi, ma;
428                 mi = self.mins;
429                 ma = self.maxs;
430
431                 precache_model(self.lodmodel1);
432                 setmodel(self, self.lodmodel1);
433                 self.lodmodelindex1 = self.modelindex;
434
435                 if(self.lodmodel2 != "")
436                 {
437                         precache_model(self.lodmodel2);
438                         setmodel(self, self.lodmodel2);
439                         self.lodmodelindex2 = self.modelindex;
440                 }
441
442                 self.modelindex = self.lodmodelindex0;
443                 setsize(self, mi, ma);
444         }
445
446         if(self.lodmodelindex1)
447                 SetCustomizer(self, LOD_customize, LOD_uncustomize);
448 }
449
450 void SetBrushEntityModel()
451 {
452         if(self.model != "")
453         {
454                 precache_model(self.model);
455                 setmodel(self, self.model); // no precision needed
456                 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
457         }
458         setorigin(self, self.origin);
459         setsize(self, self.mins, self.maxs);
460 }
461
462 /*
463 ================
464 InitTrigger
465 ================
466 */
467
468 void SetMovedir()
469 {
470         if (self.movedir != '0 0 0')
471                 self.movedir = normalize(self.movedir);
472         else
473         {
474                 if (self.angles == '0 -1 0')
475                         self.movedir = '0 0 1';
476                 else if (self.angles == '0 -2 0')
477                         self.movedir = '0 0 -1';
478                 else
479                 {
480                         makevectors (self.angles);
481                         self.movedir = v_forward;
482                 }
483         }
484
485         self.angles = '0 0 0';
486 };
487
488 void InitTrigger()
489 {
490 // trigger angles are used for one-way touches.  An angle of 0 is assumed
491 // to mean no restrictions, so use a yaw of 360 instead.
492         if (self.movedir == '0 0 0')
493         if (self.angles != '0 0 0')
494                 SetMovedir ();
495         self.solid = SOLID_TRIGGER;
496         SetBrushEntityModel();
497         self.movetype = MOVETYPE_NONE;
498         self.modelindex = 0;
499         self.model = "";
500 };
501
502 void InitSolidBSPTrigger()
503 {
504 // trigger angles are used for one-way touches.  An angle of 0 is assumed
505 // to mean no restrictions, so use a yaw of 360 instead.
506         if (self.movedir == '0 0 0')
507         if (self.angles != '0 0 0')
508                 SetMovedir ();
509         self.solid = SOLID_BSP;
510         SetBrushEntityModel();
511         self.movetype = MOVETYPE_PUSH;
512 //      self.modelindex = 0;
513         self.model = "";
514 };
515
516 void InitMovingBrushTrigger()
517 {
518 // trigger angles are used for one-way touches.  An angle of 0 is assumed
519 // to mean no restrictions, so use a yaw of 360 instead.
520         self.solid = SOLID_BSP;
521         SetBrushEntityModel();
522         self.movetype = MOVETYPE_PUSH;
523 };