1 void SUB_NullThink(void) { }
3 void() SUB_CalcMoveDone;
4 void() SUB_CalcAngleMoveDone;
5 //void() SUB_UseTargets;
23 Applies some friction to self
27 void SUB_Friction (void)
29 self.nextthink = time;
30 if(self.flags & FL_ONGROUND)
31 self.velocity = self.velocity * (1 - frametime * self.friction);
38 Makes client invisible or removes non-client
41 void SUB_VanishOrRemove (entity ent)
60 void SUB_SetFade_Think (void)
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);
70 self.nextthink = time;
77 Fade 'ent' out when time >= 'when'
80 void SUB_SetFade (entity ent, float when, float fading_time)
82 ent.fade_rate = 1/fading_time;
83 ent.think = SUB_SetFade_Think;
91 calculate self.velocity and self.nextthink to reach dest from
92 self.origin traveling at speed
95 void SUB_CalcMoveDone (void)
97 // After moving, set origin to exact final destination
99 setorigin (self, self.finaldest);
100 self.velocity = '0 0 0';
106 .float platmovetype_turn;
107 void SUB_CalcMove_controller_think (void)
118 delta = self.destvec;
119 delta2 = self.destvec2;
120 if(time < self.animstate_endtime) {
121 nexttick = time + PHYS_INPUT_FRAMETIME;
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)
129 if(self.owner.platmovetype_turn)
132 destangle = delta + 2 * delta2 * phasepos;
133 destangle = vectoangles(destangle);
134 destangle_x = -destangle_x; // flip up / down orientation
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;
144 if(nexttick < self.animstate_endtime)
145 veloc = nextpos - self.owner.origin;
147 veloc = self.finaldest - self.owner.origin;
148 veloc = veloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
150 self.owner.velocity = veloc;
151 self.nextthink = nexttick;
153 // derivative: delta + 2 * delta2 (e.g. for angle positioning)
155 self.owner.think = self.think1;
162 void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector destin)
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
168 controller.origin = org; // starting point
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)
177 void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector destin)
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
183 controller.origin = org; // starting point
186 controller.destvec = destin; // end point
187 controller.destvec2 = '0 0 0';
190 float TSPEED_TIME = -1;
191 float TSPEED_LINEAR = 0;
192 float TSPEED_START = 1;
193 float TSPEED_END = 2;
196 void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float tspeed, void() func)
202 objerror ("No speed is defined!");
205 self.finaldest = tdest;
206 self.think = SUB_CalcMoveDone;
212 traveltime = 2 * vlen(tcontrol - self.origin) / tspeed;
215 traveltime = 2 * vlen(tcontrol - tdest) / tspeed;
218 traveltime = vlen(tdest - self.origin) / tspeed;
225 if (traveltime < 0.1) // useless anim
227 self.velocity = '0 0 0';
228 self.nextthink = self.ltime + 0.1;
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;
245 // the thinking is now done by the controller
246 self.think = SUB_NullThink; // for PushMove
247 self.nextthink = self.ltime + traveltime;
255 void SUB_CalcMove (vector tdest, float tspeedtype, float tspeed, void() func)
261 objerror ("No speed is defined!");
264 self.finaldest = tdest;
265 self.think = SUB_CalcMoveDone;
267 if (tdest == self.origin)
269 self.velocity = '0 0 0';
270 self.nextthink = self.ltime + 0.1;
274 delta = tdest - self.origin;
282 traveltime = vlen (delta) / tspeed;
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?
295 self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
296 self.nextthink = self.ltime + traveltime;
300 // now just run like a bezier curve...
301 SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
304 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void() func)
311 SUB_CalcMove (tdest, tspeedtype, tspeed, func);
320 calculate self.avelocity and self.nextthink to reach destangle from
323 The calling function should make sure self.think is valid
326 void SUB_CalcAngleMoveDone (void)
328 // After rotating, set angle to exact final angle
329 self.angles = self.finalangle;
330 self.avelocity = '0 0 0';
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)
343 objerror ("No speed is defined!");
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;
357 traveltime = vlen (delta) / tspeed;
365 self.finalangle = destangle;
366 self.think = SUB_CalcAngleMoveDone;
368 if (traveltime < 0.1)
370 self.avelocity = '0 0 0';
371 self.nextthink = self.ltime + 0.1;
375 self.avelocity = delta * (1 / traveltime);
376 self.nextthink = self.ltime + traveltime;
379 void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void() func)
386 SUB_CalcAngleMove (destangle, tspeedtype, tspeed, func);