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