]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/g_subs.qc
fix timelimit -1 again
[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.dphitcontentsmask;
246         source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
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.dphitcontentsmask = 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 vector NearestPointOnBox(entity box, vector org);
376 float LOD_customize()
377 {
378         float d;
379
380         if(cvar("loddebug"))
381         {
382                 d = cvar("loddebug");
383                 if(d == 1)
384                         self.modelindex = self.lodmodelindex0;
385                 else if(d == 2)
386                         self.modelindex = self.lodmodelindex1;
387                 else // if(d == 3)
388                         self.modelindex = self.lodmodelindex2;
389                 return TRUE;
390         }
391
392         // TODO csqc network this so it only gets sent once
393         d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
394         if(d < self.loddistance1)
395                 self.modelindex = self.lodmodelindex0;
396         else if(!self.lodmodelindex2 || d < self.loddistance2)
397                 self.modelindex = self.lodmodelindex1;
398         else
399                 self.modelindex = self.lodmodelindex2;
400
401         return TRUE;
402 }
403
404 void LOD_uncustomize()
405 {
406         self.modelindex = self.lodmodelindex0;
407 }
408
409 void LODmodel_attach()
410 {
411         entity e;
412
413         if(!self.loddistance1)
414                 self.loddistance1 = 1000;
415         if(!self.loddistance2)
416                 self.loddistance2 = 2000;
417         self.lodmodelindex0 = self.modelindex;
418
419         if(self.lodtarget1 != "")
420         {
421                 e = find(world, targetname, self.lodtarget1);
422                 if(e)
423                 {
424                         self.lodmodel1 = e.model;
425                         remove(e);
426                 }
427         }
428         if(self.lodtarget2 != "")
429         {
430                 e = find(world, targetname, self.lodtarget2);
431                 if(e)
432                 {
433                         self.lodmodel2 = e.model;
434                         remove(e);
435                 }
436         }
437
438         if(self.lodmodel1 != "")
439         {
440                 vector mi, ma;
441                 mi = self.mins;
442                 ma = self.maxs;
443
444                 precache_model(self.lodmodel1);
445                 setmodel(self, self.lodmodel1);
446                 self.lodmodelindex1 = self.modelindex;
447
448                 if(self.lodmodel2 != "")
449                 {
450                         precache_model(self.lodmodel2);
451                         setmodel(self, self.lodmodel2);
452                         self.lodmodelindex2 = self.modelindex;
453                 }
454
455                 self.modelindex = self.lodmodelindex0;
456                 setsize(self, mi, ma);
457         }
458
459         if(self.lodmodelindex1)
460                 SetCustomizer(self, LOD_customize, LOD_uncustomize);
461 }
462
463 void SetBrushEntityModel()
464 {
465         if(self.model != "")
466         {
467                 precache_model(self.model);
468                 setmodel(self, self.model); // no precision needed
469                 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
470         }
471         setorigin(self, self.origin);
472         if(self.scale)
473                 setsize(self, self.mins * self.scale, self.maxs * self.scale);
474         else
475                 setsize(self, self.mins, self.maxs);
476 }
477
478 /*
479 ================
480 InitTrigger
481 ================
482 */
483
484 void SetMovedir()
485 {
486         if (self.movedir != '0 0 0')
487                 self.movedir = normalize(self.movedir);
488         else
489         {
490                 if (self.angles == '0 -1 0')
491                         self.movedir = '0 0 1';
492                 else if (self.angles == '0 -2 0')
493                         self.movedir = '0 0 -1';
494                 else
495                 {
496                         makevectors (self.angles);
497                         self.movedir = v_forward;
498                 }
499         }
500
501         self.angles = '0 0 0';
502 };
503
504 void InitTrigger()
505 {
506 // trigger angles are used for one-way touches.  An angle of 0 is assumed
507 // to mean no restrictions, so use a yaw of 360 instead.
508         if (self.movedir == '0 0 0')
509         if (self.angles != '0 0 0')
510                 SetMovedir ();
511         self.solid = SOLID_TRIGGER;
512         SetBrushEntityModel();
513         self.movetype = MOVETYPE_NONE;
514         self.modelindex = 0;
515         self.model = "";
516 };
517
518 void InitSolidBSPTrigger()
519 {
520 // trigger angles are used for one-way touches.  An angle of 0 is assumed
521 // to mean no restrictions, so use a yaw of 360 instead.
522         if (self.movedir == '0 0 0')
523         if (self.angles != '0 0 0')
524                 SetMovedir ();
525         self.solid = SOLID_BSP;
526         SetBrushEntityModel();
527         self.movetype = MOVETYPE_PUSH;
528 //      self.modelindex = 0;
529         self.model = "";
530 };
531
532 void InitMovingBrushTrigger()
533 {
534 // trigger angles are used for one-way touches.  An angle of 0 is assumed
535 // to mean no restrictions, so use a yaw of 360 instead.
536         self.solid = SOLID_BSP;
537         SetBrushEntityModel();
538         self.movetype = MOVETYPE_PUSH;
539 };