]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/g_subs.qc
Merge remote branch 'origin/terencehill/physics_panel_updates'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_subs.qc
1 void SUB_Null() {}
2 float SUB_True() { return 1; }
3 float SUB_False() { return 0; }
4
5 void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove;
6 void()  SUB_CalcMoveDone;
7 void() SUB_CalcAngleMoveDone;
8 //void() SUB_UseTargets;
9 void() SUB_Remove;
10
11 void spawnfunc_info_null (void)
12 {
13         remove(self);
14         // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
15 }
16
17 void setanim(entity e, vector anim, float looping, float override, float restart)
18 {
19         if (!anim)
20                 return; // no animation was given to us! We can't use this. 
21                 
22         if (anim_x == e.animstate_startframe)
23         if (anim_y == e.animstate_numframes)
24         if (anim_z == e.animstate_framerate)
25         {
26                 if(restart)
27                 {
28                         if(restart > 0)
29                         if(anim_y == 1) // ZYM animation
30                                 BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
31                 }
32                 else
33                         return;
34         }
35         e.animstate_startframe = anim_x;
36         e.animstate_numframes = anim_y;
37         e.animstate_framerate = anim_z;
38         e.animstate_starttime = servertime - 0.1 * serverframetime; // shift it a little bit into the past to prevent float inaccuracy hiccups
39         e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
40         e.animstate_looping = looping;
41         e.animstate_override = override;
42         e.frame = e.animstate_startframe;
43         e.frame1time = servertime;
44 }
45
46 void updateanim(entity e)
47 {
48         if (time >= e.animstate_endtime)
49         {
50                 if (e.animstate_looping)
51                 {
52                         e.animstate_starttime = e.animstate_endtime;
53                         e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
54                 }
55                 e.animstate_override = FALSE;
56         }
57         e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, e.animstate_numframes - 1);
58         //print(ftos(time), " -> ", ftos(e.frame), "\n");
59 }
60
61 vector animfixfps(entity e, vector a)
62 {
63         // multi-frame anim: keep as-is
64         if(a_y == 1)
65         {
66                 float dur;
67                 dur = frameduration(e.modelindex, a_x);
68                 if(dur > 0)
69                         a_z = 1.0 / dur;
70         }
71         return a;
72 }
73
74 /*
75 ==================
76 SUB_Remove
77
78 Remove self
79 ==================
80 */
81 void SUB_Remove (void)
82 {
83         remove (self);
84 }
85
86 /*
87 ==================
88 SUB_Friction
89
90 Applies some friction to self
91 ==================
92 */
93 .float friction;
94 void SUB_Friction (void)
95 {
96         self.nextthink = time;
97         if(self.flags & FL_ONGROUND)
98                 self.velocity = self.velocity * (1 - frametime * self.friction);
99 }
100
101 /*
102 ==================
103 SUB_VanishOrRemove
104
105 Makes client invisible or removes non-client
106 ==================
107 */
108 void SUB_VanishOrRemove (entity ent)
109 {
110         if (ent.flags & FL_CLIENT)
111         {
112                 // vanish
113                 ent.alpha = -1;
114                 ent.effects = 0;
115                 ent.glow_size = 0;
116                 ent.pflags = 0;
117         }
118         else
119         {
120                 // remove
121                 remove (ent);
122         }
123 }
124
125 void SUB_SetFade_Think (void)
126 {
127         if(self.alpha == 0)
128                 self.alpha = 1;
129         self.think = SUB_SetFade_Think;
130         self.nextthink = time;
131         self.alpha -= frametime * self.fade_rate;
132         if (self.alpha < 0.01)
133                 SUB_VanishOrRemove(self);
134         else
135                 self.nextthink = time;
136 }
137
138 /*
139 ==================
140 SUB_SetFade
141
142 Fade 'ent' out when time >= 'when'
143 ==================
144 */
145 void SUB_SetFade (entity ent, float when, float fadetime)
146 {
147         //if (ent.flags & FL_CLIENT) // && ent.deadflag != DEAD_NO)
148         //      return;
149         //ent.alpha = 1;
150         ent.fade_rate = 1/fadetime;
151         ent.think = SUB_SetFade_Think;
152         ent.nextthink = when;
153 }
154
155 /*
156 =============
157 SUB_CalcMove
158
159 calculate self.velocity and self.nextthink to reach dest from
160 self.origin traveling at speed
161 ===============
162 */
163 void SUB_CalcMoveDone (void)
164 {
165         // After moving, set origin to exact final destination
166
167         setorigin (self, self.finaldest);
168         self.velocity = '0 0 0';
169         self.nextthink = -1;
170         if (self.think1)
171                 self.think1 ();
172 }
173
174 void SUB_CalcMove_controller_think (void)
175 {
176         entity oldself;
177         float traveltime;
178         float phasepos;
179         float nexttick;
180         vector delta;
181         vector veloc;
182         vector nextpos;
183         if(time < self.animstate_endtime) {
184                 delta = self.destvec;
185                 nexttick = time + sys_frametime;
186
187                 if(nexttick < self.animstate_endtime) {
188                         traveltime = self.animstate_endtime - self.animstate_starttime;
189                         phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
190                         phasepos = 3.14159265 + (phasepos * 3.14159265); // range: [pi, 2pi]
191                         phasepos = cos(phasepos); // cos [pi, 2pi] is in [-1, 1]
192                         phasepos = phasepos + 1; // correct range to [0, 2]
193                         phasepos = phasepos / 2; // correct range to [0, 1]
194                         nextpos = self.origin + (delta * phasepos);
195
196                         veloc = nextpos - self.owner.origin;
197                         veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
198
199                 } else {
200                         veloc = self.finaldest - self.owner.origin;
201                         veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
202                 }
203                 self.owner.velocity = veloc;
204                 self.nextthink = nexttick;
205         } else {
206                 oldself = self;
207                 self.owner.think = self.think1;
208                 self = self.owner;
209                 remove(oldself);
210                 self.think();
211         }
212 }
213
214 void SUB_CalcMove (vector tdest, float tspeed, void() func)
215 {
216         vector  delta;
217         float   traveltime;
218         entity controller;
219
220         if (!tspeed)
221                 objerror ("No speed is defined!");
222
223         self.think1 = func;
224         self.finaldest = tdest;
225         self.think = SUB_CalcMoveDone;
226
227         if (tdest == self.origin)
228         {
229                 self.velocity = '0 0 0';
230                 self.nextthink = self.ltime + 0.1;
231                 return;
232         }
233
234         delta = tdest - self.origin;
235         traveltime = vlen (delta) / tspeed;
236
237         if (traveltime < 0.1)
238         {
239                 self.velocity = '0 0 0';
240                 self.nextthink = self.ltime + 0.1;
241                 return;
242         }
243
244         // Very short animations don't really show off the effect
245         // of controlled animation, so let's just use linear movement.
246         // Alternatively entities can choose to specify non-controlled movement.
247         // The only currently implemented alternative movement is linear (value 1)
248         if (traveltime < 0.15 || self.platmovetype == 1)
249         {
250                 self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
251                 self.nextthink = self.ltime + traveltime;
252                 return;
253         }
254
255         controller = spawn();
256         controller.classname = "SUB_CalcMove_controller";
257         controller.owner = self;
258         controller.origin = self.origin; // starting point
259         controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
260         controller.destvec = delta;
261         controller.animstate_starttime = time;
262         controller.animstate_endtime = time + traveltime;
263         controller.think = SUB_CalcMove_controller_think;
264         controller.think1 = self.think;
265
266         // the thinking is now done by the controller
267         self.think = SUB_Null;
268         self.nextthink = self.ltime + traveltime;
269         
270         // invoke controller
271         self = controller;
272         self.think();
273         self = self.owner;
274 }
275
276 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
277 {
278         entity  oldself;
279
280         oldself = self;
281         self = ent;
282
283         SUB_CalcMove (tdest, tspeed, func);
284
285         self = oldself;
286 }
287
288 /*
289 =============
290 SUB_CalcAngleMove
291
292 calculate self.avelocity and self.nextthink to reach destangle from
293 self.angles rotating
294
295 The calling function should make sure self.think is valid
296 ===============
297 */
298 void SUB_CalcAngleMoveDone (void)
299 {
300         // After rotating, set angle to exact final angle
301         self.angles = self.finalangle;
302         self.avelocity = '0 0 0';
303         self.nextthink = -1;
304         if (self.think1)
305                 self.think1 ();
306 }
307
308 // FIXME: I fixed this function only for rotation around the main axes
309 void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
310 {
311         vector  delta;
312         float   traveltime;
313
314         if (!tspeed)
315                 objerror ("No speed is defined!");
316
317         // take the shortest distance for the angles
318         self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5);
319         self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
320         self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
321         delta = destangle - self.angles;
322         traveltime = vlen (delta) / tspeed;
323
324         self.think1 = func;
325         self.finalangle = destangle;
326         self.think = SUB_CalcAngleMoveDone;
327
328         if (traveltime < 0.1)
329         {
330                 self.avelocity = '0 0 0';
331                 self.nextthink = self.ltime + 0.1;
332                 return;
333         }
334
335         self.avelocity = delta * (1 / traveltime);
336         self.nextthink = self.ltime + traveltime;
337 }
338
339 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeed, void() func)
340 {
341         entity  oldself;
342
343         oldself = self;
344         self = ent;
345
346         SUB_CalcAngleMove (destangle, tspeed, func);
347
348         self = oldself;
349 }
350
351 /*
352 ==================
353 main
354
355 unused but required by the engine
356 ==================
357 */
358 void main (void)
359 {
360
361 }
362
363 // Misc
364
365 /*
366 ==================
367 traceline_antilag
368
369 A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
370 Additionally it moves players back into the past before the trace and restores them afterward.
371 ==================
372 */
373 void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
374 {
375         entity player;
376         float oldsolid;
377
378         // check whether antilagged traces are enabled
379         if (lag < 0.001)
380                 lag = 0;
381         if (clienttype(forent) != CLIENTTYPE_REAL)
382                 lag = 0; // only antilag for clients
383
384         // change shooter to SOLID_BBOX so the shot can hit corpses
385         if(source)
386         {
387                 oldsolid = source.dphitcontentsmask;
388                 source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
389         }
390
391         if (lag)
392         {
393                 // take players back into the past
394                 FOR_EACH_PLAYER(player)
395                         if(player != forent)
396                                 antilag_takeback(player, time - lag);
397         }
398
399         // do the trace
400         if(wz)
401                 WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
402         else
403                 tracebox (v1, mi, ma, v2, nomonst, forent);
404
405         // restore players to current positions
406         if (lag)
407         {
408                 FOR_EACH_PLAYER(player)
409                         if(player != forent)
410                                 antilag_restore(player);
411         }
412
413         // restore shooter solid type
414         if(source)
415                 source.dphitcontentsmask = oldsolid;
416 }
417 void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
418 {
419         tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, FALSE);
420 }
421 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
422 {
423         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
424                 lag = 0;
425         traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
426 }
427 void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
428 {
429         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
430                 lag = 0;
431         tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, FALSE);
432 }
433 void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
434 {
435         tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, TRUE);
436 }
437 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
438 {
439         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
440                 lag = 0;
441         WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
442 }
443 void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
444 {
445         if (autocvar_g_antilag != 2 || source.cvar_cl_noantilag)
446                 lag = 0;
447         tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, TRUE);
448 }
449
450 float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent) // returns the number of traces done, for benchmarking
451 {
452         vector pos, dir, t;
453         float nudge;
454
455         //nudge = 2 * cvar("collision_impactnudge"); // why not?
456         nudge = 0.5;
457
458         dir = normalize(v2 - v1);
459
460         pos = v1 + dir * nudge;
461
462         float c;
463         c = 0;
464
465         for(;;)
466         {
467                 if((pos - v1) * dir >= (v2 - v1) * dir)
468                 {
469                         // went too far
470                         trace_fraction = 1;
471                         trace_endpos = v2;
472                         return c;
473                 }
474
475                 tracebox(pos, mi, ma, v2, nomonsters, forent);
476                 ++c;
477
478                 if(c == 50)
479                 {
480                         dprint("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2), "\n");
481                         dprint("  Nudging gets us nowhere at ", vtos(pos), "\n");
482                         dprint("  trace_endpos is ", vtos(trace_endpos), "\n");
483                         dprint("  trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
484                 }
485
486                 if(trace_startsolid)
487                 {
488                         // we started inside solid.
489                         // then trace from endpos to pos
490                         t = trace_endpos;
491                         tracebox(t, mi, ma, pos, nomonsters, forent);
492                         ++c;
493                         if(trace_startsolid)
494                         {
495                                 // t is still inside solid? bad
496                                 // force advance, then, and retry
497                                 pos = t + dir * nudge;
498                         }
499                         else
500                         {
501                                 // we actually LEFT solid!
502                                 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
503                                 return c;
504                         }
505                 }
506                 else
507                 {
508                         // pos is outside solid?!? but why?!? never mind, just return it.
509                         trace_endpos = pos;
510                         trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
511                         return c;
512                 }
513         }
514 }
515
516 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent)
517 {
518 #if 0
519         vector pos, dir, t;
520         float nudge;
521
522         //nudge = 2 * cvar("collision_impactnudge"); // why not?
523         nudge = 0.5;
524
525         dir = normalize(v2 - v1);
526
527         pos = v1 + dir * nudge;
528
529         for(;;)
530         {
531                 if((pos - v1) * dir >= (v2 - v1) * dir)
532                 {
533                         // went too far
534                         trace_fraction = 1;
535                         return;
536                 }
537
538                 traceline(pos, v2, nomonsters, forent);
539
540                 if(trace_startsolid)
541                 {
542                         // we started inside solid.
543                         // then trace from endpos to pos
544                         t = trace_endpos;
545                         traceline(t, pos, nomonsters, forent);
546                         if(trace_startsolid)
547                         {
548                                 // t is inside solid? bad
549                                 // force advance, then
550                                 pos = pos + dir * nudge;
551                         }
552                         else
553                         {
554                                 // we actually LEFT solid!
555                                 trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
556                                 return;
557                         }
558                 }
559                 else
560                 {
561                         // pos is outside solid?!? but why?!? never mind, just return it.
562                         trace_endpos = pos;
563                         trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
564                         return;
565                 }
566         }
567 #else
568         tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent);
569 }
570
571 /*
572 ==================
573 findbetterlocation
574
575 Returns a point at least 12 units away from walls
576 (useful for explosion animations, although the blast is performed where it really happened)
577 Ripped from DPMod
578 ==================
579 */
580 vector findbetterlocation (vector org, float mindist)
581 {
582         vector  loc;
583         vector vec;
584         float c, h;
585
586         vec = mindist * '1 0 0';
587         c = 0;
588         while (c < 6)
589         {
590                 traceline (org, org + vec, TRUE, world);
591                 vec = vec * -1;
592                 if (trace_fraction < 1)
593                 {
594                         loc = trace_endpos;
595                         traceline (loc, loc + vec, TRUE, world);
596                         if (trace_fraction >= 1)
597                                 org = loc + vec;
598                 }
599                 if (c & 1)
600                 {
601                         h = vec_y;
602                         vec_y = vec_x;
603                         vec_x = vec_z;
604                         vec_z = h;
605                 }
606                 c = c + 1;
607         }
608
609         return org;
610 }
611
612 /*
613 ==================
614 crandom
615
616 Returns a random number between -1.0 and 1.0
617 ==================
618 */
619 float crandom (void)
620 {
621         return 2 * (random () - 0.5);
622 }
623
624 /*
625 ==================
626 Angc used for animations
627 ==================
628 */
629
630
631 float angc (float a1, float a2)
632 {
633         float   a;
634
635         while (a1 > 180)
636                 a1 = a1 - 360;
637         while (a1 < -179)
638                 a1 = a1 + 360;
639
640         while (a2 > 180)
641                 a2 = a2 - 360;
642         while (a2 < -179)
643                 a2 = a2 + 360;
644
645         a = a1 - a2;
646         while (a > 180)
647                 a = a - 360;
648         while (a < -179)
649                 a = a + 360;
650
651         return a;
652 }
653
654 .string lodtarget1;
655 .string lodtarget2;
656 .string lodmodel1;
657 .string lodmodel2;
658 .float lodmodelindex0;
659 .float lodmodelindex1;
660 .float lodmodelindex2;
661 .float loddistance1;
662 .float loddistance2;
663
664 float LOD_customize()
665 {
666         float d;
667
668         if(autocvar_loddebug)
669         {
670                 d = autocvar_loddebug;
671                 if(d == 1)
672                         self.modelindex = self.lodmodelindex0;
673                 else if(d == 2 || !self.lodmodelindex2)
674                         self.modelindex = self.lodmodelindex1;
675                 else // if(d == 3)
676                         self.modelindex = self.lodmodelindex2;
677                 return TRUE;
678         }
679
680         // TODO csqc network this so it only gets sent once
681         d = vlen(NearestPointOnBox(self, other.origin) - other.origin);
682         if(d < self.loddistance1)
683                 self.modelindex = self.lodmodelindex0;
684         else if(!self.lodmodelindex2 || d < self.loddistance2)
685                 self.modelindex = self.lodmodelindex1;
686         else
687                 self.modelindex = self.lodmodelindex2;
688
689         return TRUE;
690 }
691
692 void LOD_uncustomize()
693 {
694         self.modelindex = self.lodmodelindex0;
695 }
696
697 void LODmodel_attach()
698 {
699         entity e;
700
701         if(!self.loddistance1)
702                 self.loddistance1 = 1000;
703         if(!self.loddistance2)
704                 self.loddistance2 = 2000;
705         self.lodmodelindex0 = self.modelindex;
706
707         if(self.lodtarget1 != "")
708         {
709                 e = find(world, targetname, self.lodtarget1);
710                 if(e)
711                 {
712                         self.lodmodel1 = e.model;
713                         remove(e);
714                 }
715         }
716         if(self.lodtarget2 != "")
717         {
718                 e = find(world, targetname, self.lodtarget2);
719                 if(e)
720                 {
721                         self.lodmodel2 = e.model;
722                         remove(e);
723                 }
724         }
725
726         if(autocvar_loddebug < 0)
727         {
728                 self.lodmodel1 = self.lodmodel2 = ""; // don't even initialize
729         }
730
731         if(self.lodmodel1 != "")
732         {
733                 vector mi, ma;
734                 mi = self.mins;
735                 ma = self.maxs;
736
737                 precache_model(self.lodmodel1);
738                 setmodel(self, self.lodmodel1);
739                 self.lodmodelindex1 = self.modelindex;
740
741                 if(self.lodmodel2 != "")
742                 {
743                         precache_model(self.lodmodel2);
744                         setmodel(self, self.lodmodel2);
745                         self.lodmodelindex2 = self.modelindex;
746                 }
747
748                 self.modelindex = self.lodmodelindex0;
749                 setsize(self, mi, ma);
750         }
751
752         if(self.lodmodelindex1)
753                 if not(self.SendEntity)
754                         SetCustomizer(self, LOD_customize, LOD_uncustomize);
755 }
756
757 void ApplyMinMaxScaleAngles(entity e)
758 {
759         if(e.angles_x != 0 || e.angles_z != 0 || self.avelocity_x != 0 || self.avelocity_z != 0) // "weird" rotation
760         {
761                 e.maxs = '1 1 1' * vlen(
762                         '1 0 0' * max(-e.mins_x, e.maxs_x) +
763                         '0 1 0' * max(-e.mins_y, e.maxs_y) +
764                         '0 0 1' * max(-e.mins_z, e.maxs_z)
765                 );
766                 e.mins = -e.maxs;
767         }
768         else if(e.angles_y != 0 || self.avelocity_y != 0) // yaw only is a bit better
769         {
770                 e.maxs_x = vlen(
771                         '1 0 0' * max(-e.mins_x, e.maxs_x) +
772                         '0 1 0' * max(-e.mins_y, e.maxs_y)
773                 );
774                 e.maxs_y = e.maxs_x;
775                 e.mins_x = -e.maxs_x;
776                 e.mins_y = -e.maxs_x;
777         }
778         if(e.scale)
779                 setsize(e, e.mins * e.scale, e.maxs * e.scale);
780         else
781                 setsize(e, e.mins, e.maxs);
782 }
783
784 void SetBrushEntityModel()
785 {
786         if(self.model != "")
787         {
788                 precache_model(self.model);
789                 setmodel(self, self.model); // no precision needed
790                 InitializeEntity(self, LODmodel_attach, INITPRIO_FINDTARGET);
791         }
792         setorigin(self, self.origin);
793         ApplyMinMaxScaleAngles(self);
794 }
795
796 void SetBrushEntityModelNoLOD()
797 {
798         if(self.model != "")
799         {
800                 precache_model(self.model);
801                 setmodel(self, self.model); // no precision needed
802         }
803         setorigin(self, self.origin);
804         ApplyMinMaxScaleAngles(self);
805 }
806
807 /*
808 ================
809 InitTrigger
810 ================
811 */
812
813 void SetMovedir()
814 {
815         if (self.movedir != '0 0 0')
816                 self.movedir = normalize(self.movedir);
817         else
818         {
819                 makevectors (self.angles);
820                 self.movedir = v_forward;
821         }
822
823         self.angles = '0 0 0';
824 }
825
826 void InitTrigger()
827 {
828 // trigger angles are used for one-way touches.  An angle of 0 is assumed
829 // to mean no restrictions, so use a yaw of 360 instead.
830         SetMovedir ();
831         self.solid = SOLID_TRIGGER;
832         SetBrushEntityModel();
833         self.movetype = MOVETYPE_NONE;
834         self.modelindex = 0;
835         self.model = "";
836 }
837
838 void InitSolidBSPTrigger()
839 {
840 // trigger angles are used for one-way touches.  An angle of 0 is assumed
841 // to mean no restrictions, so use a yaw of 360 instead.
842         SetMovedir ();
843         self.solid = SOLID_BSP;
844         SetBrushEntityModel();
845         self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
846 //      self.modelindex = 0;
847         self.model = "";
848 }
849
850 float InitMovingBrushTrigger()
851 {
852 // trigger angles are used for one-way touches.  An angle of 0 is assumed
853 // to mean no restrictions, so use a yaw of 360 instead.
854         self.solid = SOLID_BSP;
855         SetBrushEntityModel();
856         self.movetype = MOVETYPE_PUSH;
857         if(self.modelindex == 0)
858         {
859                 objerror("InitMovingBrushTrigger: no brushes found!");
860                 return 0;
861         }
862         return 1;
863 }