1 float STAT_MOVEFLAGS = 225;
2 float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
3 #define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
5 .entity move_groundentity;
6 .float move_suspendedinair;
7 .float move_didgravity;
9 void _Movetype_CheckVelocity() // SV_CheckVelocity
13 float _Movetype_CheckWater() // SV_CheckWater
18 void _Movetype_CheckWaterTransition() // SV_CheckWaterTransition
22 void _Movetype_Impact(entity oth) // SV_Impact
24 entity oldother, oldself;
50 void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
52 entity e, oldself, oldother;
57 for(e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
60 if(boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
65 trace_allsolid = FALSE;
66 trace_startsolid = FALSE;
68 trace_inwater = FALSE;
70 trace_endpos = e.origin;
71 trace_plane_normal = '0 0 1';
83 void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
86 if(self.solid == SOLID_BSP)
88 // TODO set the absolute bbox
97 mi = mi + self.origin;
98 ma = ma + self.origin;
100 if(self.move_flags & FL_ITEM)
123 _Movetype_LinkEdict_TouchAreaGrid();
126 float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
130 org = self.move_origin + ofs;
132 cont = self.dphitcontentsmask;
133 self.dphitcontentsmask = DPCONTENTS_SOLID;
134 tracebox(self.move_origin, self.mins, self.maxs, self.move_origin, MOVE_NOMONSTERS, self);
135 self.dphitcontentsmask = cont;
140 if(vlen(trace_endpos - self.move_origin) > 0.0001)
141 self.move_origin = trace_endpos;
145 float _Movetype_UnstickEntity() // SV_UnstickEntity
147 if(!_Movetype_TestEntityPosition('0 0 0'))
149 if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
150 if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
151 if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
152 if(!_Movetype_TestEntityPosition('0 1 0')) goto success;
153 if(!_Movetype_TestEntityPosition('-1 -1 0')) goto success;
154 if(!_Movetype_TestEntityPosition('1 -1 0')) goto success;
155 if(!_Movetype_TestEntityPosition('-1 1 0')) goto success;
156 if(!_Movetype_TestEntityPosition('1 1 0')) goto success;
158 for(i = 1; i <= 17; ++i)
160 if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
161 if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
163 dprint(sprintf(_("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.move_origin)));
166 dprint(sprintf(_("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.move_origin)));
167 _Movetype_LinkEdict(TRUE);
171 vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
173 vel = vel - ((vel * norm) * norm) * f;
175 if(vel_x > -0.1 && vel_x < 0.1) vel_x = 0;
176 if(vel_y > -0.1 && vel_y < 0.1) vel_y = 0;
177 if(vel_z > -0.1 && vel_z < 0.1) vel_z = 0;
182 void _Movetype_PushEntityTrace(vector push)
187 end = self.move_origin + push;
189 if(self.move_nomonsters)
190 type = max(0, self.move_nomonsters);
191 else if(self.move_movetype == MOVETYPE_FLYMISSILE)
193 else if(self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
194 type = MOVE_NOMONSTERS;
198 tracebox(self.move_origin, self.mins, self.maxs, end, type, self);
201 float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
203 _Movetype_PushEntityTrace(push);
205 if(trace_startsolid && failonstartsolid)
206 return trace_fraction;
208 self.move_origin = trace_endpos;
210 if(trace_fraction < 1)
211 if(self.solid >= SOLID_TRIGGER && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent)))
212 _Movetype_Impact(trace_ent);
214 return trace_fraction;
217 #define MAX_CLIP_PLANES 5
218 void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
220 if(self.move_flags & FL_ONGROUND)
222 if(self.move_velocity_z >= 1/32)
223 self.move_flags &~= FL_ONGROUND;
224 else if(!self.move_groundentity)
226 else if(self.move_suspendedinair && wasfreed(self.move_groundentity))
228 self.move_groundentity = world;
233 self.move_suspendedinair = FALSE;
235 _Movetype_CheckVelocity();
237 if(self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
239 self.move_didgravity = 1;
240 if(GRAVITY_UNAFFECTED_BY_TICRATE)
243 self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
245 self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
250 self.move_velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
252 self.move_velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
256 self.move_angles = self.move_angles + self.move_avelocity * dt;
258 float movetime, bump;
260 for(bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
263 move = self.move_velocity * movetime;
264 _Movetype_PushEntity(move, TRUE);
270 _Movetype_UnstickEntity();
271 _Movetype_PushEntity(move, FALSE);
276 if(trace_fraction == 1)
279 movetime *= 1 - min(1, trace_fraction);
281 if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
283 self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 2.0);
284 self.move_flags &~= FL_ONGROUND;
286 else if(self.move_movetype == MOVETYPE_BOUNCE)
288 float d, bouncefac, bouncestop;
290 bouncefac = self.move_bounce_factor; if(!bouncefac) bouncefac = 0.5;
291 bouncestop = self.move_bounce_stopspeed; if(!bouncestop) bouncestop = 60 / 800;
293 bouncestop *= self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
295 bouncestop *= getstatf(STAT_MOVEVARS_GRAVITY);
297 self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac);
299 d = trace_plane_normal * self.move_velocity;
300 if(trace_plane_normal_z > 0.7 && d < bouncestop && d > -bouncestop)
302 self.move_flags |= FL_ONGROUND;
303 self.move_groundentity = trace_ent;
304 self.move_velocity = '0 0 0';
305 self.move_avelocity = '0 0 0';
308 self.move_flags &~= FL_ONGROUND;
312 self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.0);
313 if(trace_plane_normal_z > 0.7)
315 self.move_flags |= FL_ONGROUND;
316 self.move_groundentity = trace_ent;
317 if(trace_ent.solid == SOLID_BSP)
318 self.move_suspendedinair = TRUE;
319 self.move_velocity = '0 0 0';
320 self.move_avelocity = '0 0 0';
323 self.move_flags &~= FL_ONGROUND;
326 // DP revision 8905 (just, WHY...)
327 if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
330 // DP revision 8918 (WHY...)
331 if(self.move_flags & FL_ONGROUND)
335 if(GRAVITY_UNAFFECTED_BY_TICRATE)
336 if(self.move_didgravity > 0)
337 if(!(self.move_flags & FL_ONGROUND))
340 self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
342 self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
345 _Movetype_CheckWaterTransition();
348 void _Movetype_Physics_Frame(float movedt)
350 self.move_didgravity = -1;
351 switch(self.move_movetype)
354 case MOVETYPE_FAKEPUSH:
355 error("SV_Physics_Pusher not implemented");
359 case MOVETYPE_FOLLOW:
360 error("SV_Physics_Follow not implemented");
362 case MOVETYPE_NOCLIP:
363 _Movetype_CheckWater();
364 self.move_origin = self.move_origin + ticrate * self.move_velocity;
365 self.move_angles = self.move_angles + ticrate * self.move_avelocity;
366 _Movetype_LinkEdict(FALSE);
369 error("SV_Physics_Step not implemented");
372 error("SV_Physics_Walk not implemented");
375 case MOVETYPE_BOUNCE:
376 case MOVETYPE_BOUNCEMISSILE:
377 case MOVETYPE_FLYMISSILE:
379 _Movetype_Physics_Toss(movedt);
384 void Movetype_Physics_NoMatchServer() // optimized
388 movedt = time - self.move_time;
389 self.move_time = time;
391 _Movetype_Physics_Frame(movedt);
395 self.avelocity = self.move_avelocity;
396 self.velocity = self.move_velocity;
397 self.angles = self.move_angles;
398 setorigin(self, self.move_origin);
401 void Movetype_Physics_MatchServer(float sloppy)
403 Movetype_Physics_MatchTicrate(ticrate, sloppy);
406 void Movetype_Physics_MatchTicrate(float tr, float sloppy) // SV_Physics_Entity
408 float n, i, dt, movedt;
412 Movetype_Physics_NoMatchServer();
416 dt = time - self.move_time;
419 n = max(0, floor(dt / tr));
421 self.move_time += n * tr;
423 if(!self.move_didgravity)
424 self.move_didgravity = ((self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) && !(self.move_flags & FL_ONGROUND));
426 for(i = 0; i < n; ++i)
428 _Movetype_Physics_Frame(movedt);
433 self.avelocity = self.move_avelocity;
435 if(dt > 0 && self.move_movetype != MOVETYPE_NONE && !(self.move_flags & FL_ONGROUND))
437 // now continue the move from move_time to time
438 self.velocity = self.move_velocity;
440 if(self.move_didgravity > 0)
442 if(GRAVITY_UNAFFECTED_BY_TICRATE)
445 self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
447 self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
452 self.velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
454 self.velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
458 self.angles = self.move_angles + dt * self.avelocity;
460 if(sloppy || self.movetype == MOVETYPE_NOCLIP)
462 setorigin(self, self.move_origin + dt * self.velocity);
466 _Movetype_PushEntityTrace(dt * self.velocity);
467 if(!trace_startsolid)
468 setorigin(self, trace_endpos);
471 if(self.move_didgravity > 0)
473 if(GRAVITY_UNAFFECTED_BY_TICRATE)
476 self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
478 self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
484 self.velocity = self.move_velocity;
485 self.angles = self.move_angles;
486 setorigin(self, self.move_origin);