]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/subs.qc
d7c813a1760e0dfec74a6a6917b4a99ba87f30f8
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / subs.qc
1 void SUB_NullThink(void) { }
2
3 void()  SUB_CalcMoveDone;
4 void() SUB_CalcAngleMoveDone;
5 //void() SUB_UseTargets;
6
7 /*
8 ==================
9 SUB_Remove
10
11 Remove self
12 ==================
13 */
14 void SUB_Remove()
15 {
16         remove (self);
17 }
18
19 /*
20 ==================
21 SUB_Friction
22
23 Applies some friction to self
24 ==================
25 */
26 .float friction;
27 void SUB_Friction (void)
28 {
29         self.nextthink = time;
30         if(self.flags & FL_ONGROUND)
31                 self.velocity = self.velocity * (1 - frametime * self.friction);
32 }
33
34 /*
35 ==================
36 SUB_VanishOrRemove
37
38 Makes client invisible or removes non-client
39 ==================
40 */
41 void SUB_VanishOrRemove (entity ent)
42 {
43         if (IS_CLIENT(ent))
44         {
45                 // vanish
46                 ent.alpha = -1;
47                 ent.effects = 0;
48 #ifdef SVQC
49                 ent.glow_size = 0;
50                 ent.pflags = 0;
51 #endif
52         }
53         else
54         {
55                 // remove
56                 remove (ent);
57         }
58 }
59
60 void SUB_SetFade_Think (void)
61 {
62         if(self.alpha == 0)
63                 self.alpha = 1;
64         self.think = SUB_SetFade_Think;
65         self.nextthink = time;
66         self.alpha -= frametime * self.fade_rate;
67         if (self.alpha < 0.01)
68                 SUB_VanishOrRemove(self);
69         else
70                 self.nextthink = time;
71 }
72
73 /*
74 ==================
75 SUB_SetFade
76
77 Fade 'ent' out when time >= 'when'
78 ==================
79 */
80 void SUB_SetFade (entity ent, float when, float fading_time)
81 {
82         ent.fade_rate = 1/fading_time;
83         ent.think = SUB_SetFade_Think;
84         ent.nextthink = when;
85 }
86
87 /*
88 =============
89 SUB_CalcMove
90
91 calculate self.velocity and self.nextthink to reach dest from
92 self.origin traveling at speed
93 ===============
94 */
95 void SUB_CalcMoveDone (void)
96 {
97         // After moving, set origin to exact final destination
98
99         setorigin (self, self.finaldest);
100         self.velocity = '0 0 0';
101         self.nextthink = -1;
102         if (self.think1)
103                 self.think1 ();
104 }
105
106 .float platmovetype_turn;
107 void SUB_CalcMove_controller_think (void)
108 {
109         entity oldself;
110         float traveltime;
111         float phasepos;
112         float nexttick;
113         vector delta;
114         vector delta2;
115         vector veloc;
116         vector angloc;
117         vector nextpos;
118         delta = self.destvec;
119         delta2 = self.destvec2;
120         if(time < self.animstate_endtime) {
121                 nexttick = time + PHYS_INPUT_FRAMETIME;
122
123                 traveltime = self.animstate_endtime - self.animstate_starttime;
124                 phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
125                 phasepos = cubic_speedfunc(self.platmovetype_start, self.platmovetype_end, phasepos);
126                 nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
127                 // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
128
129                 if(self.owner.platmovetype_turn)
130                 {
131                         vector destangle;
132                         destangle = delta + 2 * delta2 * phasepos;
133                         destangle = vectoangles(destangle);
134                         destangle_x = -destangle_x; // flip up / down orientation
135
136                         // take the shortest distance for the angles
137                         self.owner.angles_x -= 360 * floor((self.owner.angles_x - destangle_x) / 360 + 0.5);
138                         self.owner.angles_y -= 360 * floor((self.owner.angles_y - destangle_y) / 360 + 0.5);
139                         self.owner.angles_z -= 360 * floor((self.owner.angles_z - destangle_z) / 360 + 0.5);
140                         angloc = destangle - self.owner.angles;
141                         angloc = angloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
142                         self.owner.avelocity = angloc;
143                 }
144                 if(nexttick < self.animstate_endtime)
145                         veloc = nextpos - self.owner.origin;
146                 else
147                         veloc = self.finaldest - self.owner.origin;
148                 veloc = veloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
149
150                 self.owner.velocity = veloc;
151                 self.nextthink = nexttick;
152         } else {
153                 // derivative: delta + 2 * delta2 (e.g. for angle positioning)
154                 oldself = self;
155                 self.owner.think = self.think1;
156                 self = self.owner;
157                 remove(oldself);
158                 self.think();
159         }
160 }
161
162 void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector destin)
163 {
164         // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
165         // 2 * control * t - 2 * control * t * t + destin * t * t
166         // 2 * control * t + (destin - 2 * control) * t * t
167
168         controller.origin = org; // starting point
169         control -= org;
170         destin -= org;
171
172         controller.destvec = 2 * control; // control point
173         controller.destvec2 = destin - 2 * control; // quadratic part required to reach end point
174         // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (destin - control)
175 }
176
177 void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector destin)
178 {
179         // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
180         // 2 * control * t - 2 * control * t * t + destin * t * t
181         // 2 * control * t + (destin - 2 * control) * t * t
182
183         controller.origin = org; // starting point
184         destin -= org;
185
186         controller.destvec = destin; // end point
187         controller.destvec2 = '0 0 0';
188 }
189
190 float TSPEED_TIME = -1;
191 float TSPEED_LINEAR = 0;
192 float TSPEED_START = 1;
193 float TSPEED_END = 2;
194 // TODO average too?
195
196 void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
197 {
198         float   traveltime;
199         entity controller;
200
201         if (!tspeed)
202                 objerror ("No speed is defined!");
203
204         self.think1 = func;
205         self.finaldest = tdest;
206         self.think = SUB_CalcMoveDone;
207
208         switch(tspeedtype)
209         {
210                 default:
211                 case TSPEED_START:
212                         traveltime = 2 * vlen(tcontrol - self.origin) / tspeed;
213                         break;
214                 case TSPEED_END:
215                         traveltime = 2 * vlen(tcontrol - tdest)       / tspeed;
216                         break;
217                 case TSPEED_LINEAR:
218                         traveltime = vlen(tdest - self.origin)        / tspeed;
219                         break;
220                 case TSPEED_TIME:
221                         traveltime = tspeed;
222                         break;
223         }
224
225         if (traveltime < 0.1) // useless anim
226         {
227                 self.velocity = '0 0 0';
228                 self.nextthink = self.ltime + 0.1;
229                 return;
230         }
231
232         controller = spawn();
233         controller.classname = "SUB_CalcMove_controller";
234         controller.owner = self;
235         controller.platmovetype = self.platmovetype;
236         controller.platmovetype_start = self.platmovetype_start;
237         controller.platmovetype_end = self.platmovetype_end;
238         SUB_CalcMove_controller_setbezier(controller, self.origin, tcontrol, tdest);
239         controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
240         controller.animstate_starttime = time;
241         controller.animstate_endtime = time + traveltime;
242         controller.think = SUB_CalcMove_controller_think;
243         controller.think1 = self.think;
244
245         // the thinking is now done by the controller
246         self.think = SUB_NullThink; // for PushMove
247         self.nextthink = self.ltime + traveltime;
248
249         // invoke controller
250         self = controller;
251         self.think();
252         self = self.owner;
253 }
254
255 void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
256 {
257         vector  delta;
258         float   traveltime;
259
260         if (!tspeed)
261                 objerror ("No speed is defined!");
262
263         self.think1 = func;
264         self.finaldest = tdest;
265         self.think = SUB_CalcMoveDone;
266
267         if (tdest == self.origin)
268         {
269                 self.velocity = '0 0 0';
270                 self.nextthink = self.ltime + 0.1;
271                 return;
272         }
273
274         delta = tdest - self.origin;
275
276         switch(tspeedtype)
277         {
278                 default:
279                 case TSPEED_START:
280                 case TSPEED_END:
281                 case TSPEED_LINEAR:
282                         traveltime = vlen (delta) / tspeed;
283                         break;
284                 case TSPEED_TIME:
285                         traveltime = tspeed;
286                         break;
287         }
288
289         // Very short animations don't really show off the effect
290         // of controlled animation, so let's just use linear movement.
291         // Alternatively entities can choose to specify non-controlled movement.
292         // The only currently implemented alternative movement is linear (value 1)
293         if (traveltime < 0.15 || (self.platmovetype_start == 1 && self.platmovetype_end == 1)) // is this correct?
294         {
295                 self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
296                 self.nextthink = self.ltime + traveltime;
297                 return;
298         }
299
300         // now just run like a bezier curve...
301         SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
302 }
303
304 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
305 {
306         entity  oldself;
307
308         oldself = self;
309         self = ent;
310
311         SUB_CalcMove (tdest, tspeedtype, tspeed, func);
312
313         self = oldself;
314 }
315
316 /*
317 =============
318 SUB_CalcAngleMove
319
320 calculate self.avelocity and self.nextthink to reach destangle from
321 self.angles rotating
322
323 The calling function should make sure self.think is valid
324 ===============
325 */
326 void SUB_CalcAngleMoveDone (void)
327 {
328         // After rotating, set angle to exact final angle
329         self.angles = self.finalangle;
330         self.avelocity = '0 0 0';
331         self.nextthink = -1;
332         if (self.think1)
333                 self.think1 ();
334 }
335
336 // FIXME: I fixed this function only for rotation around the main axes
337 void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func)
338 {
339         vector  delta;
340         float   traveltime;
341
342         if (!tspeed)
343                 objerror ("No speed is defined!");
344
345         // take the shortest distance for the angles
346         self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5);
347         self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
348         self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
349         delta = destangle - self.angles;
350
351         switch(tspeedtype)
352         {
353                 default:
354                 case TSPEED_START:
355                 case TSPEED_END:
356                 case TSPEED_LINEAR:
357                         traveltime = vlen (delta) / tspeed;
358                         break;
359                 case TSPEED_TIME:
360                         traveltime = tspeed;
361                         break;
362         }
363
364         self.think1 = func;
365         self.finalangle = destangle;
366         self.think = SUB_CalcAngleMoveDone;
367
368         if (traveltime < 0.1)
369         {
370                 self.avelocity = '0 0 0';
371                 self.nextthink = self.ltime + 0.1;
372                 return;
373         }
374
375         self.avelocity = delta * (1 / traveltime);
376         self.nextthink = self.ltime + traveltime;
377 }
378
379 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
380 {
381         entity  oldself;
382
383         oldself = self;
384         self = ent;
385
386         SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func);
387
388         self = oldself;
389 }