]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/subs.qc
Merge branch 'master' into Mario/qc_physics_prehax
[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.SUB_NEXTTHINK = time;
30         if(self.SUB_FLAGS & FL_ONGROUND)
31                 self.SUB_VELOCITY = self.SUB_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.SUB_THINK = SUB_SetFade_Think;
65         self.SUB_NEXTTHINK = time;
66         self.alpha -= frametime * self.fade_rate;
67         if (self.alpha < 0.01)
68                 SUB_VanishOrRemove(self);
69         else
70                 self.SUB_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.SUB_THINK = SUB_SetFade_Think;
84         ent.SUB_NEXTTHINK = when;
85 }
86
87 /*
88 =============
89 SUB_CalcMove
90
91 calculate self.SUB_VELOCITY and self.SUB_NEXTTHINK to reach dest from
92 self.SUB_ORIGIN traveling at speed
93 ===============
94 */
95 void SUB_CalcMoveDone (void)
96 {
97         // After moving, set origin to exact final destination
98
99         SUB_SETORIGIN (self, self.finaldest);
100         self.SUB_VELOCITY = '0 0 0';
101         self.SUB_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         {
122                 nexttick = time + PHYS_INPUT_FRAMETIME;
123
124                 traveltime = self.animstate_endtime - self.animstate_starttime;
125                 phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
126                 phasepos = cubic_speedfunc(self.platmovetype_start, self.platmovetype_end, phasepos);
127                 nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
128                 // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
129
130                 if(self.owner.platmovetype_turn)
131                 {
132                         vector destangle;
133                         destangle = delta + 2 * delta2 * phasepos;
134                         destangle = vectoangles(destangle);
135                         destangle_x = -destangle_x; // flip up / down orientation
136
137                         // take the shortest distance for the angles
138                         SUB_ANGLES(self.owner)_x -= 360 * floor((SUB_ANGLES(self.owner)_x - destangle_x) / 360 + 0.5);
139                         SUB_ANGLES(self.owner)_y -= 360 * floor((SUB_ANGLES(self.owner)_y - destangle_y) / 360 + 0.5);
140                         SUB_ANGLES(self.owner)_z -= 360 * floor((SUB_ANGLES(self.owner)_z - destangle_z) / 360 + 0.5);
141                         angloc = destangle - SUB_ANGLES(self.owner);
142                         angloc = angloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
143                         self.owner.SUB_AVELOCITY = angloc;
144                 }
145                 if(nexttick < self.animstate_endtime)
146                         veloc = nextpos - self.owner.SUB_ORIGIN;
147                 else
148                         veloc = self.finaldest - self.owner.SUB_ORIGIN;
149                 veloc = veloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
150
151                 self.owner.SUB_VELOCITY = veloc;
152                 self.nextthink = nexttick;
153         }
154         else
155         {
156                 // derivative: delta + 2 * delta2 (e.g. for angle positioning)
157                 oldself = self;
158                 self.owner.SUB_THINK = self.think1;
159                 self = self.owner;
160                 remove(oldself);
161                 self.SUB_THINK();
162         }
163 }
164
165 void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector destin)
166 {
167         // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
168         // 2 * control * t - 2 * control * t * t + destin * t * t
169         // 2 * control * t + (destin - 2 * control) * t * t
170
171         setorigin(controller, org);
172         control -= org;
173         destin -= org;
174
175         controller.destvec = 2 * control; // control point
176         controller.destvec2 = destin - 2 * control; // quadratic part required to reach end point
177         // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (destin - control)
178 }
179
180 void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector destin)
181 {
182         // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
183         // 2 * control * t - 2 * control * t * t + destin * t * t
184         // 2 * control * t + (destin - 2 * control) * t * t
185
186         setorigin(controller, org);
187         destin -= org;
188
189         controller.destvec = destin; // end point
190         controller.destvec2 = '0 0 0';
191 }
192
193 float TSPEED_TIME = -1;
194 float TSPEED_LINEAR = 0;
195 float TSPEED_START = 1;
196 float TSPEED_END = 2;
197 // TODO average too?
198
199 void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
200 {
201         float   traveltime;
202         entity controller;
203
204         if (!tspeed)
205                 objerror ("No speed is defined!");
206
207         self.think1 = func;
208         self.finaldest = tdest;
209         self.SUB_THINK = SUB_CalcMoveDone;
210
211         switch(tspeedtype)
212         {
213                 default:
214                 case TSPEED_START:
215                         traveltime = 2 * vlen(tcontrol - self.SUB_ORIGIN) / tspeed;
216                         break;
217                 case TSPEED_END:
218                         traveltime = 2 * vlen(tcontrol - tdest)       / tspeed;
219                         break;
220                 case TSPEED_LINEAR:
221                         traveltime = vlen(tdest - self.SUB_ORIGIN)        / tspeed;
222                         break;
223                 case TSPEED_TIME:
224                         traveltime = tspeed;
225                         break;
226         }
227
228         if (traveltime < 0.1) // useless anim
229         {
230                 self.SUB_VELOCITY = '0 0 0';
231                 self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
232                 return;
233         }
234
235         controller = spawn();
236         controller.classname = "SUB_CalcMove_controller";
237         controller.owner = self;
238         controller.platmovetype = self.platmovetype;
239         controller.platmovetype_start = self.platmovetype_start;
240         controller.platmovetype_end = self.platmovetype_end;
241         SUB_CalcMove_controller_setbezier(controller, self.SUB_ORIGIN, tcontrol, tdest);
242         controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
243         controller.animstate_starttime = time;
244         controller.animstate_endtime = time + traveltime;
245         controller.think = SUB_CalcMove_controller_think;
246         controller.think1 = self.SUB_THINK;
247
248         // the thinking is now done by the controller
249         self.SUB_THINK = SUB_NullThink; // for PushMove
250         self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
251
252         // invoke controller
253         self = controller;
254         self.think();
255         self = self.owner;
256 }
257
258 void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
259 {
260         vector  delta;
261         float   traveltime;
262
263         if (!tspeed)
264                 objerror ("No speed is defined!");
265
266         self.think1 = func;
267         self.finaldest = tdest;
268         self.SUB_THINK = SUB_CalcMoveDone;
269
270         if (tdest == self.SUB_ORIGIN)
271         {
272                 self.SUB_VELOCITY = '0 0 0';
273                 self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
274                 return;
275         }
276
277         delta = tdest - self.SUB_ORIGIN;
278
279         switch(tspeedtype)
280         {
281                 default:
282                 case TSPEED_START:
283                 case TSPEED_END:
284                 case TSPEED_LINEAR:
285                         traveltime = vlen (delta) / tspeed;
286                         break;
287                 case TSPEED_TIME:
288                         traveltime = tspeed;
289                         break;
290         }
291
292         // Very short animations don't really show off the effect
293         // of controlled animation, so let's just use linear movement.
294         // Alternatively entities can choose to specify non-controlled movement.
295         // The only currently implemented alternative movement is linear (value 1)
296         if (traveltime < 0.15 || (self.platmovetype_start == 1 && self.platmovetype_end == 1)) // is this correct?
297         {
298                 self.SUB_VELOCITY = delta * (1/traveltime);     // QuakeC doesn't allow vector/float division
299                 self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
300                 return;
301         }
302
303         // now just run like a bezier curve...
304         SUB_CalcMove_Bezier((self.SUB_ORIGIN + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
305 }
306
307 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
308 {
309         entity  oldself;
310
311         oldself = self;
312         self = ent;
313
314         SUB_CalcMove (tdest, tspeedtype, tspeed, func);
315
316         self = oldself;
317 }
318
319 /*
320 =============
321 SUB_CalcAngleMove
322
323 calculate self.SUB_AVELOCITY and self.SUB_NEXTTHINK to reach destangle from
324 self.angles rotating
325
326 The calling function should make sure self.SUB_THINK is valid
327 ===============
328 */
329 void SUB_CalcAngleMoveDone (void)
330 {
331         // After rotating, set angle to exact final angle
332         self.angles = self.finalangle;
333         self.SUB_AVELOCITY = '0 0 0';
334         self.SUB_NEXTTHINK = -1;
335         if (self.think1)
336                 self.think1 ();
337 }
338
339 // FIXME: I fixed this function only for rotation around the main axes
340 void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func)
341 {
342         vector  delta;
343         float   traveltime;
344
345         if (!tspeed)
346                 objerror ("No speed is defined!");
347
348         // take the shortest distance for the angles
349         self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5);
350         self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
351         self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
352         delta = destangle - self.angles;
353
354         switch(tspeedtype)
355         {
356                 default:
357                 case TSPEED_START:
358                 case TSPEED_END:
359                 case TSPEED_LINEAR:
360                         traveltime = vlen (delta) / tspeed;
361                         break;
362                 case TSPEED_TIME:
363                         traveltime = tspeed;
364                         break;
365         }
366
367         self.think1 = func;
368         self.finalangle = destangle;
369         self.SUB_THINK = SUB_CalcAngleMoveDone;
370
371         if (traveltime < 0.1)
372         {
373                 self.SUB_AVELOCITY = '0 0 0';
374                 self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
375                 return;
376         }
377
378         self.SUB_AVELOCITY = delta * (1 / traveltime);
379         self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
380 }
381
382 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
383 {
384         entity  oldself;
385
386         oldself = self;
387         self = ent;
388
389         SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func);
390
391         self = oldself;
392 }