1 const int MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4;
2 #define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
4 .entity move_groundentity; // FIXME add move_groundnetworkentity?
5 .float move_suspendedinair;
6 .float move_didgravity;
8 void _Movetype_CheckVelocity() // SV_CheckVelocity
12 float _Movetype_CheckWater(entity ent) // SV_CheckWater
18 point = ent.move_origin;
19 point_z += (ent.mins.z + 1);
21 nativecontents = pointcontents(point);
23 if(ent.move_watertype)
24 if(ent.move_watertype != nativecontents)
26 //print(sprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", ent.move_watertype, nativecontents));
27 if(ent.contentstransition)
28 ent.contentstransition(ent.move_watertype, nativecontents);
31 ent.move_waterlevel = 0;
32 ent.move_watertype = CONTENT_EMPTY;
34 supercontents = Mod_Q1BSP_SuperContentsFromNativeContents(nativecontents);
35 if(supercontents & DPCONTENTS_LIQUIDSMASK)
37 ent.move_watertype = nativecontents;
38 ent.move_waterlevel = 1;
39 point_y = (ent.origin.y + ((ent.mins.z + ent.maxs.y) * 0.5));
40 if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
42 ent.move_waterlevel = 2;
43 point_y = ent.origin.y + ent.view_ofs.y;
44 if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
45 ent.move_waterlevel = 3;
49 return (ent.move_waterlevel > 1);
52 void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
54 float contents = pointcontents(ent.move_origin);
56 if(!ent.move_watertype)
59 if(!autocvar_cl_gameplayfix_fixedcheckwatertransition)
61 ent.move_watertype = contents;
62 ent.move_waterlevel = 1;
66 else if(ent.move_watertype != contents)
68 //print(sprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.move_origin), pointcontents(ent.move_origin), ent.move_watertype, contents));
69 if(ent.contentstransition)
70 ent.contentstransition(ent.move_watertype, contents);
73 if(contents <= CONTENT_WATER)
75 ent.move_watertype = contents;
76 ent.move_waterlevel = 1;
80 ent.move_watertype = CONTENT_EMPTY;
81 ent.move_waterlevel = (autocvar_cl_gameplayfix_fixedcheckwatertransition ? 0 : contents);
85 void _Movetype_Impact(entity oth) // SV_Impact
87 entity oldother, oldself;
113 void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
115 entity e, oldself, oldother;
120 for(e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
123 if(boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
128 trace_allsolid = false;
129 trace_startsolid = false;
131 trace_inwater = false;
133 trace_endpos = e.origin;
134 trace_plane_normal = '0 0 1';
135 trace_plane_dist = 0;
146 void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
149 if(self.solid == SOLID_BSP)
151 // TODO set the absolute bbox
160 mi = mi + self.origin;
161 ma = ma + self.origin;
163 if(self.move_flags & FL_ITEM)
186 _Movetype_LinkEdict_TouchAreaGrid();
189 float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
192 org = self.move_origin + ofs;
194 int cont = self.dphitcontentsmask;
195 self.dphitcontentsmask = DPCONTENTS_SOLID;
196 tracebox(self.move_origin, self.mins, self.maxs, self.move_origin, MOVE_NOMONSTERS, self);
197 self.dphitcontentsmask = cont;
202 if(vlen(trace_endpos - self.move_origin) > 0.0001)
203 self.move_origin = trace_endpos;
207 float _Movetype_UnstickEntity() // SV_UnstickEntity
209 if(!_Movetype_TestEntityPosition('0 0 0'))
211 if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
212 if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
213 if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
214 if(!_Movetype_TestEntityPosition('0 1 0')) goto success;
215 if(!_Movetype_TestEntityPosition('-1 -1 0')) goto success;
216 if(!_Movetype_TestEntityPosition('1 -1 0')) goto success;
217 if(!_Movetype_TestEntityPosition('-1 1 0')) goto success;
218 if(!_Movetype_TestEntityPosition('1 1 0')) goto success;
220 for(i = 1; i <= 17; ++i)
222 if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
223 if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
225 dprintf("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
228 dprintf("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
229 _Movetype_LinkEdict(true);
233 vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
235 vel = vel - ((vel * norm) * norm) * f;
237 if(vel.x > -0.1 && vel.x < 0.1) vel_x = 0;
238 if(vel.y > -0.1 && vel.y < 0.1) vel_y = 0;
239 if(vel.z > -0.1 && vel.z < 0.1) vel_z = 0;
244 void _Movetype_PushEntityTrace(vector push)
249 end = self.move_origin + push;
251 if(self.move_nomonsters)
252 type = max(0, self.move_nomonsters);
253 else if(self.move_movetype == MOVETYPE_FLYMISSILE)
255 else if(self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
256 type = MOVE_NOMONSTERS;
260 tracebox(self.move_origin, self.mins, self.maxs, end, type, self);
263 float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
265 _Movetype_PushEntityTrace(push);
267 if(trace_startsolid && failonstartsolid)
268 return trace_fraction;
270 self.move_origin = trace_endpos;
272 if(trace_fraction < 1)
273 if(self.solid >= SOLID_TRIGGER && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent)))
274 _Movetype_Impact(trace_ent);
276 return trace_fraction;
279 const float MAX_CLIP_PLANES = 5;
280 void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
282 if(self.move_flags & FL_ONGROUND)
284 if(self.move_velocity.z >= 1/32)
285 self.move_flags &= ~FL_ONGROUND;
286 else if(!self.move_groundentity)
288 else if(self.move_suspendedinair && wasfreed(self.move_groundentity))
290 self.move_groundentity = world;
295 self.move_suspendedinair = false;
297 _Movetype_CheckVelocity();
299 if(self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
301 self.move_didgravity = 1;
302 if(GRAVITY_UNAFFECTED_BY_TICRATE)
305 self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
307 self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
312 self.move_velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
314 self.move_velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
318 self.move_angles = self.move_angles + self.move_avelocity * dt;
320 float movetime, bump;
322 for(bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
325 move = self.move_velocity * movetime;
326 _Movetype_PushEntity(move, true);
332 _Movetype_UnstickEntity();
333 _Movetype_PushEntity(move, false);
338 if(trace_fraction == 1)
341 movetime *= 1 - min(1, trace_fraction);
343 if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
345 self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 2.0);
346 self.move_flags &= ~FL_ONGROUND;
348 else if(self.move_movetype == MOVETYPE_BOUNCE)
350 float d, bouncefac, bouncestop;
352 bouncefac = self.move_bounce_factor; if(!bouncefac) bouncefac = 0.5;
353 bouncestop = self.move_bounce_stopspeed; if(!bouncestop) bouncestop = 60 / 800;
355 bouncestop *= self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
357 bouncestop *= getstatf(STAT_MOVEVARS_GRAVITY);
359 self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac);
361 d = trace_plane_normal * self.move_velocity;
362 if(trace_plane_normal.z > 0.7 && d < bouncestop && d > -bouncestop)
364 self.move_flags |= FL_ONGROUND;
365 self.move_groundentity = trace_ent;
366 self.move_velocity = '0 0 0';
367 self.move_avelocity = '0 0 0';
370 self.move_flags &= ~FL_ONGROUND;
374 self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.0);
375 if(trace_plane_normal.z > 0.7)
377 self.move_flags |= FL_ONGROUND;
378 self.move_groundentity = trace_ent;
379 if(trace_ent.solid == SOLID_BSP)
380 self.move_suspendedinair = true;
381 self.move_velocity = '0 0 0';
382 self.move_avelocity = '0 0 0';
385 self.move_flags &= ~FL_ONGROUND;
388 // DP revision 8905 (just, WHY...)
389 if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
392 // DP revision 8918 (WHY...)
393 if(self.move_flags & FL_ONGROUND)
397 if(GRAVITY_UNAFFECTED_BY_TICRATE)
398 if(self.move_didgravity > 0)
399 if(!(self.move_flags & FL_ONGROUND))
402 self.move_velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
404 self.move_velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
407 _Movetype_CheckWaterTransition(self);
410 void _Movetype_Physics_Frame(float movedt)
412 self.move_didgravity = -1;
413 switch(self.move_movetype)
416 case MOVETYPE_FAKEPUSH:
417 error("SV_Physics_Pusher not implemented");
421 case MOVETYPE_FOLLOW:
422 error("SV_Physics_Follow not implemented");
424 case MOVETYPE_NOCLIP:
425 _Movetype_CheckWater(self);
426 self.move_origin = self.move_origin + ticrate * self.move_velocity;
427 self.move_angles = self.move_angles + ticrate * self.move_avelocity;
428 _Movetype_LinkEdict(false);
431 error("SV_Physics_Step not implemented");
434 error("SV_Physics_Walk not implemented");
437 case MOVETYPE_BOUNCE:
438 case MOVETYPE_BOUNCEMISSILE:
439 case MOVETYPE_FLYMISSILE:
441 _Movetype_Physics_Toss(movedt);
446 void Movetype_Physics_NoMatchServer() // optimized
450 movedt = time - self.move_time;
451 self.move_time = time;
453 _Movetype_Physics_Frame(movedt);
457 self.avelocity = self.move_avelocity;
458 self.velocity = self.move_velocity;
459 self.angles = self.move_angles;
460 setorigin(self, self.move_origin);
463 void Movetype_Physics_MatchServer(bool sloppy)
465 Movetype_Physics_MatchTicrate(ticrate, sloppy);
468 void Movetype_Physics_MatchTicrate(float tr, bool sloppy) // SV_Physics_Entity
470 float n, i, dt, movedt;
474 Movetype_Physics_NoMatchServer();
478 dt = time - self.move_time;
481 n = max(0, floor(dt / tr));
483 self.move_time += n * tr;
485 if(!self.move_didgravity)
486 self.move_didgravity = ((self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) && !(self.move_flags & FL_ONGROUND));
488 for(i = 0; i < n; ++i)
490 _Movetype_Physics_Frame(movedt);
495 self.avelocity = self.move_avelocity;
497 if(dt > 0 && self.move_movetype != MOVETYPE_NONE && !(self.move_flags & FL_ONGROUND))
499 // now continue the move from move_time to time
500 self.velocity = self.move_velocity;
502 if(self.move_didgravity > 0)
504 if(GRAVITY_UNAFFECTED_BY_TICRATE)
507 self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
509 self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
514 self.velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
516 self.velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
520 self.angles = self.move_angles + dt * self.avelocity;
522 if(sloppy || self.movetype == MOVETYPE_NOCLIP)
524 setorigin(self, self.move_origin + dt * self.velocity);
528 _Movetype_PushEntityTrace(dt * self.velocity);
529 if(!trace_startsolid)
530 setorigin(self, trace_endpos);
533 if(self.move_didgravity > 0)
535 if(GRAVITY_UNAFFECTED_BY_TICRATE)
538 self.velocity_z -= 0.5 * dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
540 self.velocity_z -= 0.5 * dt * getstatf(STAT_MOVEVARS_GRAVITY);
546 self.velocity = self.move_velocity;
547 self.angles = self.move_angles;
548 setorigin(self, self.move_origin);