1 void SUB_NullThink(void) { }
3 void() SUB_CalcMoveDone;
4 void() SUB_CalcAngleMoveDone;
5 //void() SUB_UseTargets;
11 Applies some friction to self
15 void SUB_Friction (void)
17 self.SUB_NEXTTHINK = time;
18 if(self.SUB_FLAGS & FL_ONGROUND)
19 self.SUB_VELOCITY = self.SUB_VELOCITY * (1 - frametime * self.friction);
26 Makes client invisible or removes non-client
29 void SUB_VanishOrRemove (entity ent)
48 void SUB_SetFade_Think (void)
52 self.SUB_THINK = SUB_SetFade_Think;
53 self.SUB_NEXTTHINK = time;
54 self.alpha -= frametime * self.fade_rate;
55 if (self.alpha < 0.01)
56 SUB_VanishOrRemove(self);
58 self.SUB_NEXTTHINK = time;
65 Fade 'ent' out when time >= 'when'
68 void SUB_SetFade (entity ent, float when, float fading_time)
70 ent.fade_rate = 1/fading_time;
71 ent.SUB_THINK = SUB_SetFade_Think;
72 ent.SUB_NEXTTHINK = when;
79 calculate self.SUB_VELOCITY and self.SUB_NEXTTHINK to reach dest from
80 self.SUB_ORIGIN traveling at speed
83 void SUB_CalcMoveDone (void)
85 // After moving, set origin to exact final destination
87 SUB_SETORIGIN (self, self.finaldest);
88 self.SUB_VELOCITY = '0 0 0';
89 self.SUB_NEXTTHINK = -1;
94 .float platmovetype_turn;
95 void SUB_CalcMove_controller_think (void)
106 delta = self.destvec;
107 delta2 = self.destvec2;
108 if(time < self.animstate_endtime)
110 nexttick = time + PHYS_INPUT_FRAMETIME;
112 traveltime = self.animstate_endtime - self.animstate_starttime;
113 phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
114 phasepos = cubic_speedfunc(self.platmovetype_start, self.platmovetype_end, phasepos);
115 nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
116 // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
118 if(self.owner.platmovetype_turn)
121 destangle = delta + 2 * delta2 * phasepos;
122 destangle = vectoangles(destangle);
123 destangle_x = -destangle_x; // flip up / down orientation
125 // take the shortest distance for the angles
126 SUB_ANGLES(self.owner)_x -= 360 * floor((SUB_ANGLES(self.owner)_x - destangle_x) / 360 + 0.5);
127 SUB_ANGLES(self.owner)_y -= 360 * floor((SUB_ANGLES(self.owner)_y - destangle_y) / 360 + 0.5);
128 SUB_ANGLES(self.owner)_z -= 360 * floor((SUB_ANGLES(self.owner)_z - destangle_z) / 360 + 0.5);
129 angloc = destangle - SUB_ANGLES(self.owner);
130 angloc = angloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
131 self.owner.SUB_AVELOCITY = angloc;
133 if(nexttick < self.animstate_endtime)
134 veloc = nextpos - self.owner.SUB_ORIGIN;
136 veloc = self.finaldest - self.owner.SUB_ORIGIN;
137 veloc = veloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
139 self.owner.SUB_VELOCITY = veloc;
140 self.nextthink = nexttick;
144 // derivative: delta + 2 * delta2 (e.g. for angle positioning)
146 self.owner.SUB_THINK = self.think1;
153 void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector destin)
155 // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
156 // 2 * control * t - 2 * control * t * t + destin * t * t
157 // 2 * control * t + (destin - 2 * control) * t * t
159 setorigin(controller, org);
163 controller.destvec = 2 * control; // control point
164 controller.destvec2 = destin - 2 * control; // quadratic part required to reach end point
165 // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (destin - control)
168 void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector destin)
170 // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
171 // 2 * control * t - 2 * control * t * t + destin * t * t
172 // 2 * control * t + (destin - 2 * control) * t * t
174 setorigin(controller, org);
177 controller.destvec = destin; // end point
178 controller.destvec2 = '0 0 0';
181 float TSPEED_TIME = -1;
182 float TSPEED_LINEAR = 0;
183 float TSPEED_START = 1;
184 float TSPEED_END = 2;
187 void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
193 objerror ("No speed is defined!");
196 self.finaldest = tdest;
197 self.SUB_THINK = SUB_CalcMoveDone;
203 traveltime = 2 * vlen(tcontrol - self.SUB_ORIGIN) / tspeed;
206 traveltime = 2 * vlen(tcontrol - tdest) / tspeed;
209 traveltime = vlen(tdest - self.SUB_ORIGIN) / tspeed;
216 if (traveltime < 0.1) // useless anim
218 self.SUB_VELOCITY = '0 0 0';
219 self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
223 controller = spawn();
224 controller.classname = "SUB_CalcMove_controller";
225 controller.owner = self;
226 controller.platmovetype = self.platmovetype;
227 controller.platmovetype_start = self.platmovetype_start;
228 controller.platmovetype_end = self.platmovetype_end;
229 SUB_CalcMove_controller_setbezier(controller, self.SUB_ORIGIN, tcontrol, tdest);
230 controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
231 controller.animstate_starttime = time;
232 controller.animstate_endtime = time + traveltime;
233 controller.think = SUB_CalcMove_controller_think;
234 controller.think1 = self.SUB_THINK;
236 // the thinking is now done by the controller
237 self.SUB_THINK = SUB_NullThink; // for PushMove
238 self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
246 void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
252 objerror ("No speed is defined!");
255 self.finaldest = tdest;
256 self.SUB_THINK = SUB_CalcMoveDone;
258 if (tdest == self.SUB_ORIGIN)
260 self.SUB_VELOCITY = '0 0 0';
261 self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
265 delta = tdest - self.SUB_ORIGIN;
273 traveltime = vlen (delta) / tspeed;
280 // Very short animations don't really show off the effect
281 // of controlled animation, so let's just use linear movement.
282 // Alternatively entities can choose to specify non-controlled movement.
283 // The only currently implemented alternative movement is linear (value 1)
284 if (traveltime < 0.15 || (self.platmovetype_start == 1 && self.platmovetype_end == 1)) // is this correct?
286 self.SUB_VELOCITY = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
287 self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
291 // now just run like a bezier curve...
292 SUB_CalcMove_Bezier((self.SUB_ORIGIN + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
295 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
297 SELFCALL(ent, SUB_CalcMove (tdest, tspeedtype, tspeed, func));
305 calculate self.SUB_AVELOCITY and self.SUB_NEXTTHINK to reach destangle from
308 The calling function should make sure self.SUB_THINK is valid
311 void SUB_CalcAngleMoveDone (void)
313 // After rotating, set angle to exact final angle
314 self.angles = self.finalangle;
315 self.SUB_AVELOCITY = '0 0 0';
316 self.SUB_NEXTTHINK = -1;
321 // FIXME: I fixed this function only for rotation around the main axes
322 void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func)
328 objerror ("No speed is defined!");
330 // take the shortest distance for the angles
331 self.angles_x -= 360 * floor((self.angles_x - destangle_x) / 360 + 0.5);
332 self.angles_y -= 360 * floor((self.angles_y - destangle_y) / 360 + 0.5);
333 self.angles_z -= 360 * floor((self.angles_z - destangle_z) / 360 + 0.5);
334 delta = destangle - self.angles;
342 traveltime = vlen (delta) / tspeed;
350 self.finalangle = destangle;
351 self.SUB_THINK = SUB_CalcAngleMoveDone;
353 if (traveltime < 0.1)
355 self.SUB_AVELOCITY = '0 0 0';
356 self.SUB_NEXTTHINK = self.SUB_LTIME + 0.1;
360 self.SUB_AVELOCITY = delta * (1 / traveltime);
361 self.SUB_NEXTTHINK = self.SUB_LTIME + traveltime;
364 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
366 SELFCALL(ent, SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func));