]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/g_subs.qc
The end of the start
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_subs.qc
1 void spawnfunc_info_null (void)
2 {
3         remove(self);
4         // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
5 }
6
7 void setanim(entity e, vector anim, float looping, float override, float restart)
8 {
9         if (!anim)
10                 return; // no animation was given to us! We can't use this.
11
12         if (anim_x == e.animstate_startframe)
13         if (anim_y == e.animstate_numframes)
14         if (anim_z == e.animstate_framerate)
15         {
16                 if(restart)
17                 {
18                         if(restart > 0)
19                         if(anim_y == 1) // ZYM animation
20                                 BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
21                 }
22                 else
23                         return;
24         }
25         e.animstate_startframe = anim_x;
26         e.animstate_numframes = anim_y;
27         e.animstate_framerate = anim_z;
28         e.animstate_starttime = servertime - 0.1 * serverframetime; // shift it a little bit into the past to prevent float inaccuracy hiccups
29         e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
30         e.animstate_looping = looping;
31         e.animstate_override = override;
32         e.frame = e.animstate_startframe;
33         e.frame1time = servertime;
34 }
35
36 void updateanim(entity e)
37 {
38         if (time >= e.animstate_endtime)
39         {
40                 if (e.animstate_looping)
41                 {
42                         e.animstate_starttime = e.animstate_endtime;
43                         e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
44                 }
45                 e.animstate_override = FALSE;
46         }
47         e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, e.animstate_numframes - 1);
48         //print(ftos(time), " -> ", ftos(e.frame), "\n");
49 }
50
51
52 /*
53 ==================
54 main
55
56 unused but required by the engine
57 ==================
58 */
59 void main (void)
60 {
61
62 }
63
64 // Misc
65
66 /*
67 ==================
68 traceline_antilag
69
70 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
71 Additionally it moves players back into the past before the trace and restores them afterward.
72 ==================
73 */
74 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
75 {
76         entity player;
77         float oldsolid;
78
79         // check whether antilagged traces are enabled
80         if (lag < 0.001)
81                 lag = 0;
82         if (!IS_REAL_CLIENT(forent))
83                 lag = 0; // only antilag for clients
84
85         // change shooter to SOLID_BBOX so the shot can hit corpses
86         oldsolid = source.dphitcontentsmask;
87         if(source)
88                 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
89
90         if (lag)
91         {
92                 // take players back into the past
93                 FOR_EACH_PLAYER(player)
94                         if(player != forent)
95                                 antilag_takeback(player, time - lag);
96                 FOR_EACH_MONSTER(player)
97                         antilag_takeback(player, time - lag);
98         }
99
100         // do the trace
101         if(wz)
102                 WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
103         else
104                 tracebox (v1, mi, ma, v2, nomonst, forent);
105
106         // restore players to current positions
107         if (lag)
108         {
109                 FOR_EACH_PLAYER(player)
110                         if(player != forent)
111                                 antilag_restore(player);
112                 FOR_EACH_MONSTER(player)
113                         antilag_restore(player);
114         }
115
116         // restore shooter solid type
117         if(source)
118                 source.dphitcontentsmask = oldsolid;
119 }
120 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
121 {
122         tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, FALSE);
123 }
124 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
125 {
126         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
127                 lag = 0;
128         traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
129 }
130 void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
131 {
132         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
133                 lag = 0;
134         tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, FALSE);
135 }
136 void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
137 {
138         tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, TRUE);
139 }
140 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
141 {
142         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
143                 lag = 0;
144         WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
145 }
146 void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
147 {
148         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
149                 lag = 0;
150         tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, TRUE);
151 }
152
153 float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking
154 {
155         vector pos, dir, t;
156         float nudge;
157         entity stopentity;
158
159         //nudge = 2 * cvar("collision_impactnudge"); // why not?
160         nudge = 0.5;
161
162         dir = normalize(v2 - v1);
163
164         pos = v1 + dir * nudge;
165
166         float c;
167         c = 0;
168
169         for(;;)
170         {
171                 if(pos * dir >= v2 * dir)
172                 {
173                         // went too far
174                         trace_fraction = 1;
175                         trace_endpos = v2;
176                         return c;
177                 }
178
179                 tracebox(pos, mi, ma, v2, nomonsters, forent);
180                 ++c;
181
182                 if(c == 50)
183                 {
184                         dprint("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
185                         dprint("  Nudging gets us nowhere at ", vtos(pos), "\n");
186                         dprint("  trace_endpos is ", vtos(trace_endpos), "\n");
187                         dprint("  trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
188                 }
189
190                 stopentity = trace_ent;
191
192                 if(trace_startsolid)
193                 {
194                         // we started inside solid.
195                         // then trace from endpos to pos
196                         t = trace_endpos;
197                         tracebox(t, mi, ma, pos, nomonsters, forent);
198                         ++c;
199                         if(trace_startsolid)
200                         {
201                                 // t is still inside solid? bad
202                                 // force advance, then, and retry
203                                 pos = t + dir * nudge;
204
205                                 // but if we hit an entity, stop RIGHT before it
206                                 if(stopatentity && stopentity && stopentity != ignorestopatentity)
207                                 {
208                                         trace_ent = stopentity;
209                                         trace_endpos = t;
210                                         trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
211                                         return c;
212                                 }
213                         }
214                         else
215                         {
216                                 // we actually LEFT solid!
217                                 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
218                                 return c;
219                         }
220                 }
221                 else
222                 {
223                         // pos is outside solid?!? but why?!? never mind, just return it.
224                         trace_endpos = pos;
225                         trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
226                         return c;
227                 }
228         }
229 }
230
231 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
232 {
233         tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
234 }
235
236 /*
237 ==================
238 findbetterlocation
239
240 Returns a point at least 12 units away from walls
241 (useful for explosion animations, although the blast is performed where it really happened)
242 Ripped from DPMod
243 ==================
244 */
245 vector findbetterlocation (vector org, float mindist)
246 {
247         vector  loc;
248         vector vec;
249         float c, h;
250
251         vec = mindist * '1 0 0';
252         c = 0;
253         while (c < 6)
254         {
255                 traceline (org, org + vec, TRUE, world);
256                 vec = vec * -1;
257                 if (trace_fraction < 1)
258                 {
259                         loc = trace_endpos;
260                         traceline (loc, loc + vec, TRUE, world);
261                         if (trace_fraction >= 1)
262                                 org = loc + vec;
263                 }
264                 if (c & 1)
265                 {
266                         h = vec_y;
267                         vec_y = vec_x;
268                         vec_x = vec_z;
269                         vec_z = h;
270                 }
271                 c = c + 1;
272         }
273
274         return org;
275 }
276
277 /*
278 ==================
279 crandom
280
281 Returns a random number between -1.0 and 1.0
282 ==================
283 */
284 float crandom (void)
285 {
286         return 2 * (random () - 0.5);
287 }
288
289 /*
290 ==================
291 Angc used for animations
292 ==================
293 */
294
295
296 float angc (float a1, float a2)
297 {
298         float   a;
299
300         while (a1 > 180)
301                 a1 = a1 - 360;
302         while (a1 < -179)
303                 a1 = a1 + 360;
304
305         while (a2 > 180)
306                 a2 = a2 - 360;
307         while (a2 < -179)
308                 a2 = a2 + 360;
309
310         a = a1 - a2;
311         while (a > 180)
312                 a = a - 360;
313         while (a < -179)
314                 a = a + 360;
315
316         return a;
317 }
318
319 .string lodtarget1;
320 .string lodtarget2;
321 .string lodmodel1;
322 .string lodmodel2;
323 .float lodmodelindex0;
324 .float lodmodelindex1;
325 .float lodmodelindex2;
326 .float loddistance1;
327 .float loddistance2;
328
329 float LOD_customize()
330 {
331         float d;
332
333         if(autocvar_loddebug)
334         {
335                 d = autocvar_loddebug;
336                 if(d == 1)
337                         self.modelindex = self.lodmodelindex0;
338                 else if(d == 2 || !self.lodmodelindex2)
339                         self.modelindex = self.lodmodelindex1;
340                 else // if(d == 3)
341                         self.modelindex = self.lodmodelindex2;
342                 return TRUE;
343         }
344
345         // TODO csqc network this so it only gets sent once
346         d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
347         if(d < self.loddistance1)
348                 self.modelindex = self.lodmodelindex0;
349         else if(!self.lodmodelindex2 || d < self.loddistance2)
350                 self.modelindex = self.lodmodelindex1;
351         else
352                 self.modelindex = self.lodmodelindex2;
353
354         return TRUE;
355 }
356
357 void LOD_uncustomize()
358 {
359         self.modelindex = self.lodmodelindex0;
360 }
361
362 void LODmodel_attach()
363 {
364         entity e;
365
366         if(!self.loddistance1)
367                 self.loddistance1 = 1000;
368         if(!self.loddistance2)
369                 self.loddistance2 = 2000;
370         self.lodmodelindex0 = self.modelindex;
371
372         if(self.lodtarget1 != "")
373         {
374                 e = find(world, targetname, self.lodtarget1);
375                 if(e)
376                 {
377                         self.lodmodel1 = e.model;
378                         remove(e);
379                 }
380         }
381         if(self.lodtarget2 != "")
382         {
383                 e = find(world, targetname, self.lodtarget2);
384                 if(e)
385                 {
386                         self.lodmodel2 = e.model;
387                         remove(e);
388                 }
389         }
390
391         if(autocvar_loddebug < 0)
392         {
393                 self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize
394         }
395
396         if(self.lodmodel1 != "")
397         {
398                 vector mi, ma;
399                 mi = self.mins;
400                 ma = self.maxs;
401
402                 precache_model(self.lodmodel1);
403                 setmodel(self, self.lodmodel1);
404                 self.lodmodelindex1 = self.modelindex;
405
406                 if(self.lodmodel2 != "")
407                 {
408                         precache_model(self.lodmodel2);
409                         setmodel(self, self.lodmodel2);
410                         self.lodmodelindex2 = self.modelindex;
411                 }
412
413                 self.modelindex = self.lodmodelindex0;
414                 setsize(self, mi, ma);
415         }
416
417         if(self.lodmodelindex1)
418                 if (!self.SendEntity)
419                         SetCustomizer(self, LOD_customize, LOD_uncustomize);
420 }
421
422 void ApplyMinMaxScaleAngles(entity e)
423 {
424         if(e.angles_x != 0 || e.angles_z != 0 || self.avelocity_x != 0 || self.avelocity_z != 0) // "weird" rotation
425         {
426                 e.maxs = '1 1 1' * vlen(
427                         '1 0 0' * max(-e.mins_x, e.maxs_x) +
428                         '0 1 0' * max(-e.mins_y, e.maxs_y) +
429                         '0 0 1' * max(-e.mins_z, e.maxs_z)
430                 );
431                 e.mins = -e.maxs;
432         }
433         else if(e.angles_y != 0 || self.avelocity_y != 0) // yaw only is a bit better
434         {
435                 e.maxs_x = vlen(
436                         '1 0 0' * max(-e.mins_x, e.maxs_x) +
437                         '0 1 0' * max(-e.mins_y, e.maxs_y)
438                 );
439                 e.maxs_y = e.maxs_x;
440                 e.mins_x = -e.maxs_x;
441                 e.mins_y = -e.maxs_x;
442         }
443         if(e.scale)
444                 setsize(e, e.mins * e.scale, e.maxs * e.scale);
445         else
446                 setsize(e, e.mins, e.maxs);
447 }
448
449 void SetBrushEntityModel()
450 {
451         if(self.model != "")
452         {
453                 precache_model(self.model);
454                 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
455                 {
456                         vector mi = self.mins;
457                         vector ma = self.maxs;
458                         setmodel(self, self.model); // no precision needed
459                         setsize(self, mi, ma);
460                 }
461                 else
462                         setmodel(self, self.model); // no precision needed
463                 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
464         }
465         setorigin(self, self.origin);
466         ApplyMinMaxScaleAngles(self);
467 }
468
469 void SetBrushEntityModelNoLOD()
470 {
471         if(self.model != "")
472         {
473                 precache_model(self.model);
474                 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
475                 {
476                         vector mi = self.mins;
477                         vector ma = self.maxs;
478                         setmodel(self, self.model); // no precision needed
479                         setsize(self, mi, ma);
480                 }
481                 else
482                         setmodel(self, self.model); // no precision needed
483         }
484         setorigin(self, self.origin);
485         ApplyMinMaxScaleAngles(self);
486 }
487
488 /*
489 ================
490 InitTrigger
491 ================
492 */
493
494 void SetMovedir()
495 {
496         if (self.movedir != '0 0 0')
497                 self.movedir = normalize(self.movedir);
498         else
499         {
500                 makevectors (self.angles);
501                 self.movedir = v_forward;
502         }
503
504         self.angles = '0 0 0';
505 }
506
507 void InitTrigger()
508 {
509 // trigger angles are used for one-way touches.  An angle of 0 is assumed
510 // to mean no restrictions, so use a yaw of 360 instead.
511         SetMovedir ();
512         self.solid = SOLID_TRIGGER;
513         SetBrushEntityModel();
514         self.movetype = MOVETYPE_NONE;
515         self.modelindex = 0;
516         self.model = "";
517 }
518
519 void InitSolidBSPTrigger()
520 {
521 // trigger angles are used for one-way touches.  An angle of 0 is assumed
522 // to mean no restrictions, so use a yaw of 360 instead.
523         SetMovedir ();
524         self.solid = SOLID_BSP;
525         SetBrushEntityModel();
526         self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
527 //      self.modelindex = 0;
528         self.model = "";
529 }
530
531 float InitMovingBrushTrigger()
532 {
533 // trigger angles are used for one-way touches.  An angle of 0 is assumed
534 // to mean no restrictions, so use a yaw of 360 instead.
535         self.solid = SOLID_BSP;
536         SetBrushEntityModel();
537         self.movetype = MOVETYPE_PUSH;
538         if(self.modelindex == 0)
539         {
540                 objerror("InitMovingBrushTrigger: no brushes found!");
541                 return 0;
542         }
543         return 1;
544 }