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