2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
29 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33 corpses are SOLID_NOT and MOVETYPE_TOSS
34 crates are SOLID_BBOX and MOVETYPE_TOSS
35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
38 solid_edge items only clip against bsp models.
42 #define MOVE_EPSILON 0.01
44 void SV_Physics_Toss (prvm_edict_t *ent);
46 int SV_GetPitchSign(prvm_edict_t *ent)
50 (model = SV_GetModelFromEdict(ent))
52 model->type == mod_alias
55 (((unsigned char)PRVM_serveredictfloat(ent, pflags)) & PFLAGS_FULLDYNAMIC)
57 ((gamemode == GAME_TENEBRAE) && ((unsigned int)PRVM_serveredictfloat(ent, effects) & (16 | 32)))
65 ===============================================================================
69 ===============================================================================
72 int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
76 int dphitcontentsmask = (int)PRVM_serveredictfloat(passedict, dphitcontentsmask);
77 if (dphitcontentsmask)
78 return dphitcontentsmask;
79 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_SLIDEBOX)
81 if ((int)PRVM_serveredictfloat(passedict, flags) & FL_MONSTER)
82 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP;
84 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP;
86 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_CORPSE)
87 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
88 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_TRIGGER)
89 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
91 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
94 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
102 trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
104 int i, bodysupercontents;
107 prvm_edict_t *traceowner, *touch;
109 // bounding box of entire move area
110 vec3_t clipboxmins, clipboxmaxs;
111 // size when clipping against monsters
112 vec3_t clipmins2, clipmaxs2;
113 // start and end origin of move
117 // matrices to transform into/out of other entity's space
118 matrix4x4_t matrix, imatrix;
119 // model of other entity
121 // list of entities to test for collisions
123 static prvm_edict_t *touchedicts[MAX_EDICTS];
125 //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
127 VectorCopy(start, clipstart);
128 VectorClear(clipmins2);
129 VectorClear(clipmaxs2);
130 #if COLLISIONPARANOID >= 3
131 Con_Printf("move(%f %f %f)", clipstart[0], clipstart[1], clipstart[2]);
135 Collision_ClipPointToWorld(&cliptrace, sv.worldmodel, clipstart, hitsupercontentsmask);
136 cliptrace.bmodelstartsolid = cliptrace.startsolid;
137 if (cliptrace.startsolid || cliptrace.fraction < 1)
138 cliptrace.ent = prog->edicts;
139 if (type == MOVE_WORLDONLY)
142 if (type == MOVE_MISSILE)
144 // LordHavoc: modified this, was = -15, now -= 15
145 for (i = 0;i < 3;i++)
152 // create the bounding box of the entire move
153 for (i = 0;i < 3;i++)
155 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
156 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
159 // debug override to test against everything
160 if (sv_debugmove.integer)
162 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
163 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
166 // if the passedict is world, make it NULL (to avoid two checks each time)
167 if (passedict == prog->edicts)
169 // precalculate prog value for passedict for comparisons
170 passedictprog = PRVM_EDICT_TO_PROG(passedict);
171 // precalculate passedict's owner edict pointer for comparisons
172 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
175 // because this uses World_EntitiestoBox, we know all entity boxes overlap
176 // the clip region, so we can skip culling checks in the loop below
177 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
178 if (numtouchedicts > MAX_EDICTS)
180 // this never happens
181 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
182 numtouchedicts = MAX_EDICTS;
184 for (i = 0;i < numtouchedicts;i++)
186 touch = touchedicts[i];
188 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
190 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
195 // don't clip against self
196 if (passedict == touch)
198 // don't clip owned entities against owner
199 if (traceowner == touch)
201 // don't clip owner against owned entities
202 if (passedictprog == PRVM_serveredictedict(touch, owner))
204 // don't clip points against points (they can't collide)
205 if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
209 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
211 // might interact, so do an exact clip
213 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
215 model = SV_GetModelFromEdict(touch);
216 pitchsign = SV_GetPitchSign(touch);
219 Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
221 Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
222 Matrix4x4_Invert_Simple(&imatrix, &matrix);
223 VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
224 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
225 VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
226 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
227 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
229 Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
231 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
243 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
244 trace_t SV_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
246 trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
249 int i, bodysupercontents;
252 prvm_edict_t *traceowner, *touch;
254 // bounding box of entire move area
255 vec3_t clipboxmins, clipboxmaxs;
256 // size when clipping against monsters
257 vec3_t clipmins2, clipmaxs2;
258 // start and end origin of move
259 vec3_t clipstart, clipend;
262 // matrices to transform into/out of other entity's space
263 matrix4x4_t matrix, imatrix;
264 // model of other entity
266 // list of entities to test for collisions
268 static prvm_edict_t *touchedicts[MAX_EDICTS];
269 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
273 if (VectorCompare(start, pEnd))
274 return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
276 if(collision_endposnudge.value > 0)
278 // TRICK: make the trace 1 qu longer!
279 VectorSubtract(pEnd, start, end);
280 len = VectorNormalizeLength(end);
281 VectorMA(pEnd, collision_endposnudge.value, end, end);
284 VectorCopy(pEnd, end);
286 if (VectorCompare(start, end))
287 return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
290 //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
292 VectorCopy(start, clipstart);
293 VectorCopy(end, clipend);
294 VectorClear(clipmins2);
295 VectorClear(clipmaxs2);
296 #if COLLISIONPARANOID >= 3
297 Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
301 Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, false);
302 cliptrace.bmodelstartsolid = cliptrace.startsolid;
303 if (cliptrace.startsolid || cliptrace.fraction < 1)
304 cliptrace.ent = prog->edicts;
305 if (type == MOVE_WORLDONLY)
308 if (type == MOVE_MISSILE)
310 // LordHavoc: modified this, was = -15, now -= 15
311 for (i = 0;i < 3;i++)
318 // create the bounding box of the entire move
319 for (i = 0;i < 3;i++)
321 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
322 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
325 // debug override to test against everything
326 if (sv_debugmove.integer)
328 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
329 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
332 // if the passedict is world, make it NULL (to avoid two checks each time)
333 if (passedict == prog->edicts)
335 // precalculate prog value for passedict for comparisons
336 passedictprog = PRVM_EDICT_TO_PROG(passedict);
337 // precalculate passedict's owner edict pointer for comparisons
338 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
341 // because this uses World_EntitiestoBox, we know all entity boxes overlap
342 // the clip region, so we can skip culling checks in the loop below
343 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
344 if (numtouchedicts > MAX_EDICTS)
346 // this never happens
347 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
348 numtouchedicts = MAX_EDICTS;
350 for (i = 0;i < numtouchedicts;i++)
352 touch = touchedicts[i];
354 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
356 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
361 // don't clip against self
362 if (passedict == touch)
364 // don't clip owned entities against owner
365 if (traceowner == touch)
367 // don't clip owner against owned entities
368 if (passedictprog == PRVM_serveredictedict(touch, owner))
370 // don't clip points against points (they can't collide)
371 if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
375 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
377 // might interact, so do an exact clip
379 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
381 model = SV_GetModelFromEdict(touch);
382 pitchsign = SV_GetPitchSign(touch);
385 Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
387 Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
388 Matrix4x4_Invert_Simple(&imatrix, &matrix);
389 VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
390 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
391 VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
392 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
393 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
395 Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false);
397 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
401 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
402 if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
403 Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
413 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
414 #if COLLISIONPARANOID >= 1
415 trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
417 trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
420 #if COLLISIONPARANOID >= 1
421 trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
423 trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
427 vec3_t hullmins, hullmaxs;
428 int i, bodysupercontents;
432 prvm_edict_t *traceowner, *touch;
434 // bounding box of entire move area
435 vec3_t clipboxmins, clipboxmaxs;
436 // size of the moving object
437 vec3_t clipmins, clipmaxs;
438 // size when clipping against monsters
439 vec3_t clipmins2, clipmaxs2;
440 // start and end origin of move
441 vec3_t clipstart, clipend;
444 // matrices to transform into/out of other entity's space
445 matrix4x4_t matrix, imatrix;
446 // model of other entity
448 // list of entities to test for collisions
450 static prvm_edict_t *touchedicts[MAX_EDICTS];
451 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
455 if (VectorCompare(mins, maxs))
457 vec3_t shiftstart, shiftend;
458 VectorAdd(start, mins, shiftstart);
459 VectorAdd(pEnd, mins, shiftend);
460 if (VectorCompare(start, pEnd))
461 trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
463 trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
464 VectorSubtract(trace.endpos, mins, trace.endpos);
468 if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
470 // TRICK: make the trace 1 qu longer!
471 VectorSubtract(pEnd, start, end);
472 len = VectorNormalizeLength(end);
473 VectorMA(pEnd, collision_endposnudge.value, end, end);
476 VectorCopy(pEnd, end);
478 if (VectorCompare(mins, maxs))
480 vec3_t shiftstart, shiftend;
481 VectorAdd(start, mins, shiftstart);
482 VectorAdd(end, mins, shiftend);
483 if (VectorCompare(start, end))
484 trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
486 trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
487 VectorSubtract(trace.endpos, mins, trace.endpos);
492 VectorCopy(start, clipstart);
493 VectorCopy(end, clipend);
494 VectorCopy(mins, clipmins);
495 VectorCopy(maxs, clipmaxs);
496 VectorCopy(mins, clipmins2);
497 VectorCopy(maxs, clipmaxs2);
498 #if COLLISIONPARANOID >= 3
499 Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
503 Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
504 cliptrace.bmodelstartsolid = cliptrace.startsolid;
505 if (cliptrace.startsolid || cliptrace.fraction < 1)
506 cliptrace.ent = prog->edicts;
507 if (type == MOVE_WORLDONLY)
510 if (type == MOVE_MISSILE)
512 // LordHavoc: modified this, was = -15, now -= 15
513 for (i = 0;i < 3;i++)
520 // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
521 if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize)
522 sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs);
525 VectorCopy(clipmins, hullmins);
526 VectorCopy(clipmaxs, hullmaxs);
529 // create the bounding box of the entire move
530 for (i = 0;i < 3;i++)
532 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
533 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
536 // debug override to test against everything
537 if (sv_debugmove.integer)
539 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
540 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
543 // if the passedict is world, make it NULL (to avoid two checks each time)
544 if (passedict == prog->edicts)
546 // precalculate prog value for passedict for comparisons
547 passedictprog = PRVM_EDICT_TO_PROG(passedict);
548 // figure out whether this is a point trace for comparisons
549 pointtrace = VectorCompare(clipmins, clipmaxs);
550 // precalculate passedict's owner edict pointer for comparisons
551 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
554 // because this uses World_EntitiestoBox, we know all entity boxes overlap
555 // the clip region, so we can skip culling checks in the loop below
556 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
557 if (numtouchedicts > MAX_EDICTS)
559 // this never happens
560 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
561 numtouchedicts = MAX_EDICTS;
563 for (i = 0;i < numtouchedicts;i++)
565 touch = touchedicts[i];
567 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
569 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
574 // don't clip against self
575 if (passedict == touch)
577 // don't clip owned entities against owner
578 if (traceowner == touch)
580 // don't clip owner against owned entities
581 if (passedictprog == PRVM_serveredictedict(touch, owner))
583 // don't clip points against points (they can't collide)
584 if (pointtrace && VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
588 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
590 // might interact, so do an exact clip
592 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
594 model = SV_GetModelFromEdict(touch);
595 pitchsign = SV_GetPitchSign(touch);
598 Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
600 Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
601 Matrix4x4_Invert_Simple(&imatrix, &matrix);
602 VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
603 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
604 VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
605 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
606 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
608 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
610 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
614 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
615 if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
616 Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
621 #if COLLISIONPARANOID >= 1
622 trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
627 trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask);
630 VectorCopy(trace.endpos, temp);
631 endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask).startsolid;
632 #if COLLISIONPARANOID < 3
633 if (trace.startsolid || endstuck)
635 Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, PRVM_serveredictvector(passedict, origin)[0], PRVM_serveredictvector(passedict, origin)[1], PRVM_serveredictvector(passedict, origin)[2], end[0] - PRVM_serveredictvector(passedict, origin)[0], end[1] - PRVM_serveredictvector(passedict, origin)[1], end[2] - PRVM_serveredictvector(passedict, origin)[2], trace.fraction, trace.endpos[0] - PRVM_serveredictvector(passedict, origin)[0], trace.endpos[1] - PRVM_serveredictvector(passedict, origin)[1], trace.endpos[2] - PRVM_serveredictvector(passedict, origin)[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : "");
641 int SV_PointSuperContents(const vec3_t point)
643 int supercontents = 0;
647 // matrices to transform into/out of other entity's space
648 matrix4x4_t matrix, imatrix;
649 // model of other entity
652 // list of entities to test for collisions
654 static prvm_edict_t *touchedicts[MAX_EDICTS];
656 // get world supercontents at this point
657 if (sv.worldmodel && sv.worldmodel->PointSuperContents)
658 supercontents = sv.worldmodel->PointSuperContents(sv.worldmodel, 0, point);
660 // if sv_gameplayfix_swiminbmodels is off we're done
661 if (!sv_gameplayfix_swiminbmodels.integer)
662 return supercontents;
664 // get list of entities at this point
665 numtouchedicts = SV_EntitiesInBox(point, point, MAX_EDICTS, touchedicts);
666 if (numtouchedicts > MAX_EDICTS)
668 // this never happens
669 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
670 numtouchedicts = MAX_EDICTS;
672 for (i = 0;i < numtouchedicts;i++)
674 touch = touchedicts[i];
676 // we only care about SOLID_BSP for pointcontents
677 if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
680 // might interact, so do an exact clip
681 model = SV_GetModelFromEdict(touch);
682 if (!model || !model->PointSuperContents)
684 Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
685 Matrix4x4_Invert_Simple(&imatrix, &matrix);
686 Matrix4x4_Transform(&imatrix, point, transformed);
687 frame = (int)PRVM_serveredictfloat(touch, frame);
688 supercontents |= model->PointSuperContents(model, bound(0, frame, (model->numframes - 1)), transformed);
691 return supercontents;
695 ===============================================================================
697 Linking entities into the world culling system
699 ===============================================================================
702 int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts)
704 vec3_t paddedmins, paddedmaxs;
705 if (maxedicts < 1 || resultedicts == NULL)
707 VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
708 VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
709 if (sv_areadebug.integer)
711 int numresultedicts = 0;
714 for (edictindex = 1;edictindex < prog->num_edicts;edictindex++)
716 ed = PRVM_EDICT_NUM(edictindex);
717 if (!ed->priv.required->free && BoxesOverlap(PRVM_serveredictvector(ed, absmin), PRVM_serveredictvector(ed, absmax), paddedmins, paddedmaxs))
719 resultedicts[numresultedicts++] = ed;
720 if (numresultedicts == maxedicts)
724 return numresultedicts;
727 return World_EntitiesInBox(&sv.world, paddedmins, paddedmaxs, maxedicts, resultedicts);
730 void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
732 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch);
733 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent);
734 PRVM_serverglobalfloat(time) = sv.time;
735 PRVM_serverglobalfloat(trace_allsolid) = false;
736 PRVM_serverglobalfloat(trace_startsolid) = false;
737 PRVM_serverglobalfloat(trace_fraction) = 1;
738 PRVM_serverglobalfloat(trace_inwater) = false;
739 PRVM_serverglobalfloat(trace_inopen) = true;
740 VectorCopy (PRVM_serveredictvector(touch, origin), PRVM_serverglobalvector(trace_endpos));
741 VectorSet (PRVM_serverglobalvector(trace_plane_normal), 0, 0, 1);
742 PRVM_serverglobalfloat(trace_plane_dist) = 0;
743 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(ent);
744 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
745 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
746 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
747 PRVM_serverglobalstring(trace_dphittexturename) = 0;
748 PRVM_ExecuteProgram (PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
751 void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
753 int i, numtouchedicts, old_self, old_other;
755 static prvm_edict_t *touchedicts[MAX_EDICTS];
757 if (ent == prog->edicts)
758 return; // don't add the world
760 if (ent->priv.server->free)
763 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
766 // build a list of edicts to touch, because the link loop can be corrupted
767 // by IncreaseEdicts called during touch functions
768 numtouchedicts = SV_EntitiesInBox(ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
769 if (numtouchedicts > MAX_EDICTS)
771 // this never happens
772 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
773 numtouchedicts = MAX_EDICTS;
776 old_self = PRVM_serverglobaledict(self);
777 old_other = PRVM_serverglobaledict(other);
778 for (i = 0;i < numtouchedicts;i++)
780 touch = touchedicts[i];
781 if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch))
783 SV_LinkEdict_TouchAreaGrid_Call(touch, ent);
786 PRVM_serverglobaledict(self) = old_self;
787 PRVM_serverglobaledict(other) = old_other;
790 static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
794 Matrix4x4_CreateFromQuakeEntity(&m, 0, 0, 0, angles[PITCH], angles[YAW], angles[ROLL], 1.0);
796 v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
797 VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs);
798 v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
799 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
800 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
801 v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
802 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
803 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
804 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
805 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
806 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
807 v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
808 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
809 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
810 v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
811 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
812 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
813 v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
814 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
815 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
816 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
817 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
818 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
827 void SV_LinkEdict (prvm_edict_t *ent)
833 if (ent == prog->edicts)
834 return; // don't add the world
836 if (ent->priv.server->free)
839 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
840 if (modelindex < 0 || modelindex >= MAX_MODELS)
842 Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
845 model = SV_GetModelByIndex(modelindex);
847 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
848 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
849 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
853 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_PHYSICS)
855 // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
856 // TODO special handling for spheres?
857 RotateBBox(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, angles), mins, maxs);
858 VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins);
859 VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs);
861 else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
865 if (!model->TraceBox)
866 Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
868 if (PRVM_serveredictvector(ent, angles)[0] || PRVM_serveredictvector(ent, angles)[2] || PRVM_serveredictvector(ent, avelocity)[0] || PRVM_serveredictvector(ent, avelocity)[2])
870 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins);
871 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs);
873 else if (PRVM_serveredictvector(ent, angles)[1] || PRVM_serveredictvector(ent, avelocity)[1])
875 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmins, mins);
876 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmaxs, maxs);
880 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins);
881 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs);
886 // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
887 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
888 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
893 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
894 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
898 // to make items easier to pick up and allow them to be grabbed off
899 // of shelves, the abs sizes are expanded
901 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
912 // because movement is clipped an epsilon away from an actual edge,
913 // we must fully check even when bounding boxes don't quite touch
922 VectorCopy(mins, PRVM_serveredictvector(ent, absmin));
923 VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
925 World_LinkEdict(&sv.world, ent, mins, maxs);
929 ===============================================================================
933 ===============================================================================
938 SV_TestEntityPosition
940 returns true if the entity is in solid currently
943 static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
948 contents = SV_GenericHitSuperContentsMask(ent);
949 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
950 trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents);
951 if (trace.startsupercontents & contents)
955 if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs)))
957 // q1bsp/hlbsp use hulls and if the entity does not exactly match
958 // a hull size it is incorrectly tested, so this code tries to
959 // 'fix' it slightly...
960 // FIXME: this breaks entities larger than the hull size
963 VectorAdd(org, PRVM_serveredictvector(ent, mins), m1);
964 VectorAdd(org, PRVM_serveredictvector(ent, maxs), m2);
965 VectorSubtract(m2, m1, s);
966 #define EPSILON (1.0f / 32.0f)
967 if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
968 if (s[1] >= EPSILON*2) {m1[1] += EPSILON;m2[1] -= EPSILON;}
969 if (s[2] >= EPSILON*2) {m1[2] += EPSILON;m2[2] -= EPSILON;}
970 for (i = 0;i < 8;i++)
972 v[0] = (i & 1) ? m2[0] : m1[0];
973 v[1] = (i & 2) ? m2[1] : m1[1];
974 v[2] = (i & 4) ? m2[2] : m1[2];
975 if (SV_PointSuperContents(v) & contents)
980 // if the trace found a better position for the entity, move it there
981 if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001)
984 // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
985 VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
987 // verify if the endpos is REALLY outside solid
988 VectorCopy(trace.endpos, org);
989 trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), org, MOVE_NOMONSTERS, ent, contents);
991 Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
993 VectorCopy(org, PRVM_serveredictvector(ent, origin));
1004 void SV_CheckAllEnts (void)
1007 prvm_edict_t *check;
1009 // see if any solid entities are inside the final position
1010 check = PRVM_NEXT_EDICT(prog->edicts);
1011 for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check))
1013 if (check->priv.server->free)
1015 if (PRVM_serveredictfloat(check, movetype) == MOVETYPE_PUSH
1016 || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NONE
1017 || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FOLLOW
1018 || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NOCLIP
1019 || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FLY_WORLDONLY)
1022 if (SV_TestEntityPosition (check, vec3_origin))
1023 Con_Print("entity in invalid position\n");
1027 // DRESK - Support for Entity Contents Transition Event
1030 SV_CheckContentsTransition
1032 returns true if entity had a valid contentstransition function call
1035 int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
1037 int bValidFunctionCall;
1039 // Default Valid Function Call to False
1040 bValidFunctionCall = false;
1042 if(PRVM_serveredictfloat(ent, watertype) != nContents)
1043 { // Changed Contents
1044 // Acquire Contents Transition Function from QC
1045 if(PRVM_serveredictfunction(ent, contentstransition))
1046 { // Valid Function; Execute
1047 // Assign Valid Function
1048 bValidFunctionCall = true;
1049 // Prepare Parameters (Original Contents, New Contents)
1050 // Original Contents
1051 PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
1053 PRVM_G_FLOAT(OFS_PARM1) = nContents;
1055 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1056 // Execute VM Function
1057 PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
1061 // Return if Function Call was Valid
1062 return bValidFunctionCall;
1071 void SV_CheckVelocity (prvm_edict_t *ent)
1079 for (i=0 ; i<3 ; i++)
1081 if (IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
1083 Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1084 PRVM_serveredictvector(ent, velocity)[i] = 0;
1086 if (IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
1088 Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1089 PRVM_serveredictvector(ent, origin)[i] = 0;
1093 // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
1094 // player_run/player_stand1 does not horribly malfunction if the
1095 // velocity becomes a denormalized float
1096 if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001)
1097 VectorClear(PRVM_serveredictvector(ent, velocity));
1099 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
1100 wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity));
1101 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
1103 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
1104 PRVM_serveredictvector(ent, velocity)[0] *= wishspeed;
1105 PRVM_serveredictvector(ent, velocity)[1] *= wishspeed;
1106 PRVM_serveredictvector(ent, velocity)[2] *= wishspeed;
1114 Runs thinking code if time. There is some play in the exact time the think
1115 function will be called, because it is called before any movement is done
1116 in a frame. Not used for pushmove objects, because they must be exact.
1117 Returns false if the entity removed itself.
1120 qboolean SV_RunThink (prvm_edict_t *ent)
1124 // don't let things stay in the past.
1125 // it is possible to start that way by a trigger with a local time.
1126 if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime)
1129 for (iterations = 0;iterations < 128 && !ent->priv.server->free;iterations++)
1131 PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink));
1132 PRVM_serveredictfloat(ent, nextthink) = 0;
1133 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1134 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1135 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1136 // mods often set nextthink to time to cause a think every frame,
1137 // we don't want to loop in that case, so exit if the new nextthink is
1138 // <= the time the qc was told, also exit if it is past the end of the
1140 if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
1143 return !ent->priv.server->free;
1150 Two entities have touched, so run their touch functions
1153 extern void VM_SetTraceGlobals(const trace_t *trace);
1154 extern sizebuf_t vm_tempstringsbuf;
1155 void SV_Impact (prvm_edict_t *e1, trace_t *trace)
1157 int restorevm_tempstringsbuf_cursize;
1158 int old_self, old_other;
1159 prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
1161 old_self = PRVM_serverglobaledict(self);
1162 old_other = PRVM_serverglobaledict(other);
1163 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1165 VM_SetTraceGlobals(trace);
1167 PRVM_serverglobalfloat(time) = sv.time;
1168 if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
1170 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e1);
1171 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e2);
1172 PRVM_ExecuteProgram (PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
1175 if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
1177 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2);
1178 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1);
1179 VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos));
1180 VectorNegate(trace->plane.normal, PRVM_serverglobalvector(trace_plane_normal));
1181 PRVM_serverglobalfloat(trace_plane_dist) = -trace->plane.dist;
1182 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(e1);
1183 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
1184 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
1185 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
1186 PRVM_serverglobalstring(trace_dphittexturename) = 0;
1187 PRVM_ExecuteProgram (PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
1190 PRVM_serverglobaledict(self) = old_self;
1191 PRVM_serverglobaledict(other) = old_other;
1192 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1200 Slide off of the impacting object
1201 returns the blocked flags (1 = floor, 2 = step / wall)
1204 #define STOP_EPSILON 0.1
1205 void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
1210 backoff = -DotProduct (in, normal) * overbounce;
1211 VectorMA(in, backoff, normal, out);
1213 for (i = 0;i < 3;i++)
1214 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
1223 The basic solid body movement clip that slides along multiple planes
1224 Returns the clipflags if the velocity was modified (hit something solid)
1228 8 = teleported by touch method
1229 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
1232 static float SV_Gravity (prvm_edict_t *ent);
1233 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
1234 #define MAX_CLIP_PLANES 5
1235 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask, float stepheight)
1237 int blocked, bumpcount;
1238 int i, j, numplanes;
1239 float d, time_left, gravity;
1240 vec3_t dir, push, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
1249 if(sv_gameplayfix_nogravityonground.integer)
1250 if((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
1251 applygravity = false;
1255 if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
1257 gravity = SV_Gravity(ent) * 0.5f;
1258 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1262 applygravity = false;
1263 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
1267 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1268 VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
1271 for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
1273 if (!PRVM_serveredictvector(ent, velocity)[0] && !PRVM_serveredictvector(ent, velocity)[1] && !PRVM_serveredictvector(ent, velocity)[2])
1276 VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
1277 if(!SV_PushEntity(&trace, ent, push, false, false))
1279 // we got teleported by a touch function
1280 // let's abort the move
1285 if (trace.fraction == 1)
1287 if (trace.plane.normal[2])
1289 if (trace.plane.normal[2] > 0.7)
1296 Con_Printf ("SV_FlyMove: !trace.ent");
1297 trace.ent = prog->edicts;
1300 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1301 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1304 else if (stepheight)
1306 // step - handle it immediately
1312 //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1313 VectorSet(steppush, 0, 0, stepheight);
1314 VectorCopy(PRVM_serveredictvector(ent, origin), org);
1315 if(!SV_PushEntity(&steptrace, ent, steppush, false, false))
1320 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1321 if(!SV_PushEntity(&steptrace2, ent, push, false, false))
1326 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1327 VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
1328 if(!SV_PushEntity(&steptrace3, ent, steppush, false, false))
1333 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1334 // accept the new position if it made some progress...
1335 if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
1337 //Con_Printf("accepted (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
1339 VectorCopy(PRVM_serveredictvector(ent, origin), trace.endpos);
1340 time_left *= 1 - trace.fraction;
1346 //Con_Printf("REJECTED (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
1347 VectorCopy(org, PRVM_serveredictvector(ent, origin));
1352 // step - return it to caller
1354 // save the trace for player extrafriction
1356 VectorCopy(trace.plane.normal, stepnormal);
1358 if (trace.fraction >= 0.001)
1360 // actually covered some distance
1361 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1365 time_left *= 1 - trace.fraction;
1367 // clipped to another plane
1368 if (numplanes >= MAX_CLIP_PLANES)
1370 // this shouldn't really happen
1371 VectorClear(PRVM_serveredictvector(ent, velocity));
1377 for (i = 0;i < numplanes;i++)
1378 if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
1382 VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity));
1387 VectorCopy(trace.plane.normal, planes[numplanes]);
1390 // modify original_velocity so it parallels all of the clip planes
1391 for (i = 0;i < numplanes;i++)
1393 ClipVelocity(original_velocity, planes[i], new_velocity, 1);
1394 for (j = 0;j < numplanes;j++)
1399 if (DotProduct(new_velocity, planes[j]) < 0)
1409 // go along this plane
1410 VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity));
1414 // go along the crease
1417 VectorClear(PRVM_serveredictvector(ent, velocity));
1421 CrossProduct(planes[0], planes[1], dir);
1422 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
1423 VectorNormalize(dir);
1424 d = DotProduct(dir, PRVM_serveredictvector(ent, velocity));
1425 VectorScale(dir, d, PRVM_serveredictvector(ent, velocity));
1428 // if current velocity is against the original velocity,
1429 // stop dead to avoid tiny occilations in sloping corners
1430 if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0)
1432 VectorClear(PRVM_serveredictvector(ent, velocity));
1437 //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - prog->edicts, blocked, PRVM_serveredictvector(ent, velocity)[0], PRVM_serveredictvector(ent, velocity)[1], PRVM_serveredictvector(ent, velocity)[2]);
1440 if ((blocked & 1) == 0 && bumpcount > 1)
1442 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
1443 // flag ONGROUND if there's ground under it
1444 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask);
1448 // LordHavoc: this came from QW and allows you to get out of water more easily
1449 if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
1450 VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
1451 if (applygravity && !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
1452 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1462 static float SV_Gravity (prvm_edict_t *ent)
1466 ent_gravity = PRVM_serveredictfloat(ent, gravity);
1469 return ent_gravity * sv_gravity.value * sv.frametime;
1474 ===============================================================================
1478 ===============================================================================
1481 static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
1486 vec3_t stuckmins, stuckmaxs;
1487 vec3_t goodmins, goodmaxs;
1491 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1492 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1493 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1494 VectorCopy(pivot, goodmins);
1495 VectorCopy(pivot, goodmaxs);
1496 for (bump = 0;bump < 6;bump++)
1498 int coord = 2-(bump >> 1);
1499 //int coord = (bump >> 1);
1500 int dir = (bump & 1);
1503 for(subbump = 0; ; ++subbump)
1505 VectorCopy(stuckorigin, testorigin);
1509 testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord];
1514 testorigin[coord] += stuckmins[coord] - goodmins[coord];
1517 stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1518 if (stucktrace.bmodelstartsolid)
1520 // BAD BAD, can't fix that
1524 if (stucktrace.fraction >= 1)
1529 // BAD BAD, can't fix that
1533 // we hit something... let's move out of it
1534 VectorSubtract(stucktrace.endpos, testorigin, move);
1535 nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant
1536 VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin);
1540 Con_Printf("subbump: %d\n", subbump);
1546 goodmaxs[coord] = stuckmaxs[coord];
1551 goodmins[coord] = stuckmins[coord];
1556 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1561 static qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
1566 vec3_t stuckmins, stuckmaxs;
1568 vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
1569 if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
1570 separation = 0.0f; // when using hulls, it can not be enlarged
1571 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1572 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1573 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1574 stuckmins[0] -= separation;
1575 stuckmins[1] -= separation;
1576 stuckmins[2] -= separation;
1577 stuckmaxs[0] += separation;
1578 stuckmaxs[1] += separation;
1579 stuckmaxs[2] += separation;
1580 for (bump = 0;bump < 10;bump++)
1582 stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1583 if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
1585 // found a good location, use it
1586 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1589 nudge = -stucktrace.startdepth;
1590 VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
1599 Does not change the entities velocity at all
1600 The trace struct is filled with the trace that has been done.
1601 Returns true if the push did not result in the entity being teleported by QC code.
1604 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
1613 solid = (int)PRVM_serveredictfloat(ent, solid);
1614 movetype = (int)PRVM_serveredictfloat(ent, movetype);
1615 VectorCopy(PRVM_serveredictvector(ent, mins), mins);
1616 VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
1618 // move start position out of solids
1619 if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
1621 SV_NudgeOutOfSolid(ent);
1624 VectorCopy(PRVM_serveredictvector(ent, origin), start);
1625 VectorAdd(start, push, end);
1627 if (movetype == MOVETYPE_FLYMISSILE)
1628 type = MOVE_MISSILE;
1629 else if (movetype == MOVETYPE_FLY_WORLDONLY)
1630 type = MOVE_WORLDONLY;
1631 else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
1632 type = MOVE_NOMONSTERS; // only clip against bmodels
1636 *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
1637 if (trace->bmodelstartsolid && failonbmodelstartsolid)
1640 VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
1642 ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
1647 if(!trace->startsolid)
1648 if(SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid)
1650 Con_Printf("something eeeeevil happened\n");
1655 SV_LinkEdict_TouchAreaGrid(ent);
1657 if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
1658 SV_Impact (ent, trace);
1660 if(ent->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT)
1662 ent->priv.required->mark = 0;
1665 else if(ent->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
1667 ent->priv.required->mark = 0;
1672 Con_Printf("The edict mark had been overwritten! Please debug this.\n");
1684 void SV_PushMove (prvm_edict_t *pusher, float movetime)
1687 int pusherowner, pusherprog;
1690 float savesolid, movetime2, pushltime;
1691 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org;
1693 int numcheckentities;
1694 static prvm_edict_t *checkentities[MAX_EDICTS];
1695 dp_model_t *pushermodel;
1696 trace_t trace, trace2;
1697 matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
1698 static unsigned short moved_edicts[MAX_EDICTS];
1701 if (!PRVM_serveredictvector(pusher, velocity)[0] && !PRVM_serveredictvector(pusher, velocity)[1] && !PRVM_serveredictvector(pusher, velocity)[2] && !PRVM_serveredictvector(pusher, avelocity)[0] && !PRVM_serveredictvector(pusher, avelocity)[1] && !PRVM_serveredictvector(pusher, avelocity)[2])
1703 PRVM_serveredictfloat(pusher, ltime) += movetime;
1707 switch ((int) PRVM_serveredictfloat(pusher, solid))
1709 // LordHavoc: valid pusher types
1712 case SOLID_SLIDEBOX:
1713 case SOLID_CORPSE: // LordHavoc: this would be weird...
1715 // LordHavoc: no collisions
1718 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1719 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1720 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1721 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1722 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1723 PRVM_serveredictfloat(pusher, ltime) += movetime;
1724 SV_LinkEdict(pusher);
1727 Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
1730 index = (int) PRVM_serveredictfloat(pusher, modelindex);
1731 if (index < 1 || index >= MAX_MODELS)
1733 Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
1736 pushermodel = SV_GetModelByIndex(index);
1737 pusherowner = PRVM_serveredictedict(pusher, owner);
1738 pusherprog = PRVM_EDICT_TO_PROG(pusher);
1740 rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0;
1742 movetime2 = movetime;
1743 VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
1744 VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
1745 if (moveangle[0] || moveangle[2])
1747 for (i = 0;i < 3;i++)
1751 mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1752 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1756 mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1757 maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1761 else if (moveangle[1])
1763 for (i = 0;i < 3;i++)
1767 mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1768 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1772 mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1773 maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1779 for (i = 0;i < 3;i++)
1783 mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1784 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1788 mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1789 maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1794 VectorNegate (moveangle, a);
1795 AngleVectorsFLU (a, forward, left, up);
1797 VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
1798 VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
1799 pushltime = PRVM_serveredictfloat(pusher, ltime);
1801 // move the pusher to its final position
1803 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1804 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1805 PRVM_serveredictfloat(pusher, ltime) += movetime;
1806 SV_LinkEdict(pusher);
1808 pushermodel = SV_GetModelFromEdict(pusher);
1809 Matrix4x4_CreateFromQuakeEntity(&pusherfinalmatrix, PRVM_serveredictvector(pusher, origin)[0], PRVM_serveredictvector(pusher, origin)[1], PRVM_serveredictvector(pusher, origin)[2], PRVM_serveredictvector(pusher, angles)[0], PRVM_serveredictvector(pusher, angles)[1], PRVM_serveredictvector(pusher, angles)[2], 1);
1810 Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
1812 savesolid = PRVM_serveredictfloat(pusher, solid);
1814 // see if any solid entities are inside the final position
1817 if (PRVM_serveredictfloat(pusher, movetype) == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
1818 numcheckentities = 0;
1819 else // MOVETYPE_PUSH
1820 numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
1821 for (e = 0;e < numcheckentities;e++)
1823 prvm_edict_t *check = checkentities[e];
1824 int movetype = (int)PRVM_serveredictfloat(check, movetype);
1829 case MOVETYPE_FOLLOW:
1830 case MOVETYPE_NOCLIP:
1831 case MOVETYPE_FLY_WORLDONLY:
1837 if (PRVM_serveredictedict(check, owner) == pusherprog)
1840 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1843 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1845 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1846 check->priv.server->waterposition_forceupdate = true;
1848 checkcontents = SV_GenericHitSuperContentsMask(check);
1850 // if the entity is standing on the pusher, it will definitely be moved
1851 // if the entity is not standing on the pusher, but is in the pusher's
1852 // final position, move it
1853 if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
1855 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
1856 //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1857 if (!trace.startsolid)
1859 //Con_Printf("- not in solid\n");
1864 VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot);
1865 //VectorClear(pivot);
1870 VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org);
1871 VectorAdd (org, pivot, org);
1872 org2[0] = DotProduct (org, forward);
1873 org2[1] = DotProduct (org, left);
1874 org2[2] = DotProduct (org, up);
1875 VectorSubtract (org2, org, move);
1876 VectorAdd (move, move1, move);
1879 VectorCopy (move1, move);
1881 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1883 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1884 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1885 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1887 // physics objects need better collisions than this code can do
1888 if (movetype == MOVETYPE_PHYSICS)
1890 VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
1891 SV_LinkEdict(check);
1892 SV_LinkEdict_TouchAreaGrid(check);
1896 // try moving the contacted entity
1897 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1898 if(!SV_PushEntity (&trace, check, move, true, true))
1900 // entity "check" got teleported
1901 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1902 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1903 continue; // pushed enough
1905 // FIXME: turn players specially
1906 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1907 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1908 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1910 // this trace.fraction < 1 check causes items to fall off of pushers
1911 // if they pass under or through a wall
1912 // the groundentity check causes items to fall off of ledges
1913 if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
1914 PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1916 // if it is still inside the pusher, block
1917 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
1918 if (trace.startsolid)
1921 if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
1923 // hack to invoke all necessary movement triggers
1925 if(!SV_PushEntity(&trace2, check, move2, true, true))
1927 // entity "check" got teleported
1934 // still inside pusher, so it's really blocked
1937 if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1939 if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER)
1942 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1943 VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs));
1947 VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1948 VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1949 PRVM_serveredictfloat(pusher, ltime) = pushltime;
1950 SV_LinkEdict(pusher);
1952 // move back any entities we already moved
1953 for (i = 0;i < num_moved;i++)
1955 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1956 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1957 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
1961 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
1962 if (PRVM_serveredictfunction(pusher, blocked))
1964 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
1965 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
1966 PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
1971 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1972 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1973 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1982 void SV_Physics_Pusher (prvm_edict_t *ent)
1984 float thinktime, oldltime, movetime;
1986 oldltime = PRVM_serveredictfloat(ent, ltime);
1988 thinktime = PRVM_serveredictfloat(ent, nextthink);
1989 if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
1991 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
1996 movetime = sv.frametime;
1999 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
2000 SV_PushMove (ent, movetime);
2002 if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
2004 PRVM_serveredictfloat(ent, nextthink) = 0;
2005 PRVM_serverglobalfloat(time) = sv.time;
2006 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2007 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
2008 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
2014 ===============================================================================
2018 ===============================================================================
2021 static float unstickoffsets[] =
2023 // poutting -/+z changes first as they are least weird
2038 typedef enum unstickresult_e
2046 unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
2050 // if not stuck in a bmodel, just return
2051 if (!SV_TestEntityPosition(ent, vec3_origin))
2052 return UNSTICK_GOOD;
2054 for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
2056 if (!SV_TestEntityPosition(ent, unstickoffsets + i))
2058 VectorCopy(unstickoffsets + i, offset);
2060 //SV_LinkEdict_TouchAreaGrid(ent);
2061 return UNSTICK_UNSTUCK;
2065 maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
2066 // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
2068 for(i = 2; i <= maxunstick; ++i)
2070 VectorClear(offset);
2072 if (!SV_TestEntityPosition(ent, offset))
2075 //SV_LinkEdict_TouchAreaGrid(ent);
2076 return UNSTICK_UNSTUCK;
2079 if (!SV_TestEntityPosition(ent, offset))
2082 //SV_LinkEdict_TouchAreaGrid(ent);
2083 return UNSTICK_UNSTUCK;
2087 return UNSTICK_STUCK;
2090 qboolean SV_UnstickEntity (prvm_edict_t *ent)
2093 switch(SV_UnstickEntityReturnOffset(ent, offset))
2097 case UNSTICK_UNSTUCK:
2098 Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
2101 if (developer_extra.integer)
2102 Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2105 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2114 This is a big hack to try and fix the rare case of getting stuck in the world
2118 void SV_CheckStuck (prvm_edict_t *ent)
2122 switch(SV_UnstickEntityReturnOffset(ent, offset))
2125 VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
2127 case UNSTICK_UNSTUCK:
2128 Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
2131 VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
2132 if (!SV_TestEntityPosition(ent, offset))
2134 Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2136 //SV_LinkEdict_TouchAreaGrid(ent);
2139 Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2142 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2152 qboolean SV_CheckWater (prvm_edict_t *ent)
2155 int nNativeContents;
2158 point[0] = PRVM_serveredictvector(ent, origin)[0];
2159 point[1] = PRVM_serveredictvector(ent, origin)[1];
2160 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2162 // DRESK - Support for Entity Contents Transition Event
2163 // NOTE: Some logic needed to be slightly re-ordered
2164 // to not affect performance and allow for the feature.
2166 // Acquire Super Contents Prior to Resets
2167 cont = SV_PointSuperContents(point);
2168 // Acquire Native Contents Here
2169 nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
2171 // DRESK - Support for Entity Contents Transition Event
2172 if(PRVM_serveredictfloat(ent, watertype))
2173 // Entity did NOT Spawn; Check
2174 SV_CheckContentsTransition(ent, nNativeContents);
2177 PRVM_serveredictfloat(ent, waterlevel) = 0;
2178 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2179 cont = SV_PointSuperContents(point);
2180 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2182 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2183 PRVM_serveredictfloat(ent, waterlevel) = 1;
2184 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2185 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2187 PRVM_serveredictfloat(ent, waterlevel) = 2;
2188 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2189 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2190 PRVM_serveredictfloat(ent, waterlevel) = 3;
2194 return PRVM_serveredictfloat(ent, waterlevel) > 1;
2203 void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2206 vec3_t forward, into, side;
2208 AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
2209 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2211 // cut the tangential velocity
2212 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2213 VectorScale (stepnormal, i, into);
2214 VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
2215 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2216 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2222 =====================
2225 Player has come to a dead stop, possibly due to the problem with limited
2226 float precision at some angle joins in the BSP hull.
2228 Try fixing by pushing one pixel in each direction.
2230 This is a hack, but in the interest of good gameplay...
2231 ======================
2233 int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2238 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
2241 for (i=0 ; i<8 ; i++)
2243 // try pushing a little in an axial direction
2246 case 0: dir[0] = 2; dir[1] = 0; break;
2247 case 1: dir[0] = 0; dir[1] = 2; break;
2248 case 2: dir[0] = -2; dir[1] = 0; break;
2249 case 3: dir[0] = 0; dir[1] = -2; break;
2250 case 4: dir[0] = 2; dir[1] = 2; break;
2251 case 5: dir[0] = -2; dir[1] = 2; break;
2252 case 6: dir[0] = 2; dir[1] = -2; break;
2253 case 7: dir[0] = -2; dir[1] = -2; break;
2256 SV_PushEntity (&trace, ent, dir, false, true);
2258 // retry the original move
2259 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2260 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2261 PRVM_serveredictvector(ent, velocity)[2] = 0;
2262 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
2264 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2265 || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2267 Con_DPrint("TryUnstick - success.\n");
2271 // go back to the original pos and try again
2272 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
2276 VectorClear (PRVM_serveredictvector(ent, velocity));
2277 Con_DPrint("TryUnstick - failure.\n");
2283 =====================
2286 Only used by players
2287 ======================
2289 void SV_WalkMove (prvm_edict_t *ent)
2293 //int originalmove_clip;
2294 int originalmove_flags;
2295 int originalmove_groundentity;
2296 int hitsupercontentsmask;
2298 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
2299 trace_t downtrace, trace;
2300 qboolean applygravity;
2302 // if frametime is 0 (due to client sending the same timestamp twice),
2304 if (sv.frametime <= 0)
2307 if (sv_gameplayfix_unstickplayers.integer)
2308 SV_CheckStuck (ent);
2310 applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2312 hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2314 SV_CheckVelocity(ent);
2316 // do a regular slide move unless it looks like you ran into a step
2317 oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2319 VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2320 VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2322 clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2324 if(sv_gameplayfix_downtracesupportsongroundflag.integer)
2327 // only try this if there was no floor in the way in the trace (no,
2328 // this check seems to be not REALLY necessary, because if clip & 1,
2329 // our trace will hit that thing too)
2330 VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
2331 VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
2332 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
2333 type = MOVE_MISSILE;
2334 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY)
2335 type = MOVE_WORLDONLY;
2336 else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
2337 type = MOVE_NOMONSTERS; // only clip against bmodels
2340 trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
2341 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2342 clip |= 1; // but we HAVE found a floor
2345 // if the move did not hit the ground at any point, we're not on ground
2347 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2349 SV_CheckVelocity(ent);
2351 SV_LinkEdict_TouchAreaGrid(ent);
2353 if(clip & 8) // teleport
2356 if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2359 if (sv_nostep.integer)
2362 VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2363 VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2364 //originalmove_clip = clip;
2365 originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2366 originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2368 // if move didn't block on a step, return
2371 // if move was not trying to move into the step, return
2372 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2375 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
2377 // return if gibbed by a trigger
2378 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
2381 // only step up while jumping if that is enabled
2382 if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
2383 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2387 // try moving up and forward to go up a step
2388 // back to start pos
2389 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2390 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2393 VectorClear (upmove);
2394 upmove[2] = sv_stepheight.value;
2395 if(!SV_PushEntity(&trace, ent, upmove, false, true))
2397 // we got teleported when upstepping... must abort the move
2402 PRVM_serveredictvector(ent, velocity)[2] = 0;
2403 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
2404 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2407 // we got teleported when upstepping... must abort the move
2408 // note that z velocity handling may not be what QC expects here, but we cannot help it
2412 SV_CheckVelocity(ent);
2414 SV_LinkEdict_TouchAreaGrid(ent);
2416 // check for stuckness, possibly due to the limited precision of floats
2417 // in the clipping hulls
2419 && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2420 && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2422 //Con_Printf("wall\n");
2423 // stepping up didn't make any progress, revert to original move
2424 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2425 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2426 //clip = originalmove_clip;
2427 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2428 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2429 // now try to unstick if needed
2430 //clip = SV_TryUnstick (ent, oldvel);
2434 //Con_Printf("step - ");
2436 // extra friction based on view angle
2437 if (clip & 2 && sv_wallfriction.integer)
2438 SV_WallFriction (ent, stepnormal);
2440 // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2441 else if (!sv_gameplayfix_stepdown.integer || PRVM_serveredictfloat(ent, waterlevel) >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2445 VectorClear (downmove);
2446 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2447 if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
2449 // we got teleported when downstepping... must abort the move
2453 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2455 // this has been disabled so that you can't jump when you are stepping
2456 // up while already jumping (also known as the Quake2 double jump bug)
2458 // LordHavoc: disabled this check so you can walk on monsters/players
2459 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2461 //Con_Printf("onground\n");
2462 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2463 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
2469 //Con_Printf("slope\n");
2470 // if the push down didn't end up on good ground, use the move without
2471 // the step up. This happens near wall / slope combinations, and can
2472 // cause the player to hop up higher on a slope too steep to climb
2473 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2474 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2475 //clip = originalmove_clip;
2476 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2477 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2480 SV_CheckVelocity(ent);
2482 SV_LinkEdict_TouchAreaGrid(ent);
2485 //============================================================================
2491 Entities that are "stuck" to another entity
2494 void SV_Physics_Follow (prvm_edict_t *ent)
2496 vec3_t vf, vr, vu, angles, v;
2500 if (!SV_RunThink (ent))
2503 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2504 e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
2505 if (PRVM_serveredictvector(e, angles)[0] == PRVM_serveredictvector(ent, punchangle)[0] && PRVM_serveredictvector(e, angles)[1] == PRVM_serveredictvector(ent, punchangle)[1] && PRVM_serveredictvector(e, angles)[2] == PRVM_serveredictvector(ent, punchangle)[2])
2507 // quick case for no rotation
2508 VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
2512 angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
2513 angles[1] = PRVM_serveredictvector(ent, punchangle)[1];
2514 angles[2] = PRVM_serveredictvector(ent, punchangle)[2];
2515 AngleVectors (angles, vf, vr, vu);
2516 v[0] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[0] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[0] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[0];
2517 v[1] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[1] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[1] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[1];
2518 v[2] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[2] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[2] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[2];
2519 angles[0] = -PRVM_serveredictvector(e, angles)[0];
2520 angles[1] = PRVM_serveredictvector(e, angles)[1];
2521 angles[2] = PRVM_serveredictvector(e, angles)[2];
2522 AngleVectors (angles, vf, vr, vu);
2523 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2524 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2525 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2527 VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
2529 //SV_LinkEdict_TouchAreaGrid(ent);
2533 ==============================================================================
2537 ==============================================================================
2542 SV_CheckWaterTransition
2546 void SV_CheckWaterTransition (prvm_edict_t *ent)
2548 // LordHavoc: bugfixes in this function are keyed to the sv_gameplayfix_bugfixedcheckwatertransition cvar - if this cvar is 0 then all the original bugs should be reenabled for compatibility
2550 cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
2551 if (!PRVM_serveredictfloat(ent, watertype))
2553 // just spawned here
2554 if (!sv_gameplayfix_fixedcheckwatertransition.integer)
2556 PRVM_serveredictfloat(ent, watertype) = cont;
2557 PRVM_serveredictfloat(ent, waterlevel) = 1;
2561 // DRESK - Support for Entity Contents Transition Event
2562 // NOTE: Call here BEFORE updating the watertype below,
2563 // and suppress watersplash sound if a valid function
2564 // call was made to allow for custom "splash" sounds.
2565 else if( !SV_CheckContentsTransition(ent, cont) )
2566 { // Contents Transition Function Invalid; Potentially Play Water Sound
2567 // check if the entity crossed into or out of water
2568 if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
2569 SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false, 1.0f);
2572 if (cont <= CONTENTS_WATER)
2574 PRVM_serveredictfloat(ent, watertype) = cont;
2575 PRVM_serveredictfloat(ent, waterlevel) = 1;
2579 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2580 PRVM_serveredictfloat(ent, waterlevel) = sv_gameplayfix_fixedcheckwatertransition.integer ? 0 : cont;
2588 Toss, bounce, and fly movement. When onground, do nothing.
2592 void SV_Physics_Toss (prvm_edict_t *ent)
2598 prvm_edict_t *groundentity;
2599 float d, ent_gravity;
2603 // if onground, return without moving
2604 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2606 groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
2607 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2609 // don't stick to ground if onground and moving upward
2610 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2612 else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
2614 // we can trust FL_ONGROUND if groundentity is world because it never moves
2617 else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
2619 // if ent was supported by a brush model on previous frame,
2620 // and groundentity is now freed, set groundentity to 0 (world)
2621 // which leaves it suspended in the air
2622 PRVM_serveredictedict(ent, groundentity) = 0;
2623 if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
2626 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2628 // don't slide if still touching the groundentity
2632 ent->priv.server->suspendedinairflag = false;
2634 SV_CheckVelocity (ent);
2637 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2638 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
2641 VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2643 movetime = sv.frametime;
2644 for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2647 VectorScale(PRVM_serveredictvector(ent, velocity), movetime, move);
2648 if(!SV_PushEntity(&trace, ent, move, true, true))
2649 return; // teleported
2650 if (ent->priv.server->free)
2652 if (trace.bmodelstartsolid)
2654 // try to unstick the entity
2655 if (sv_gameplayfix_unstickentities.integer)
2656 SV_UnstickEntity(ent);
2657 if(!SV_PushEntity(&trace, ent, move, false, true))
2658 return; // teleported
2659 if (ent->priv.server->free)
2662 if (trace.fraction == 1)
2664 movetime *= 1 - min(1, trace.fraction);
2665 switch((int)PRVM_serveredictfloat(ent, movetype))
2667 case MOVETYPE_BOUNCEMISSILE:
2668 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2670 bouncefactor = 1.0f;
2672 ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2673 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2674 if (!sv_gameplayfix_slidemoveprojectiles.integer)
2677 case MOVETYPE_BOUNCE:
2678 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2680 bouncefactor = 0.5f;
2682 bouncestop = PRVM_serveredictfloat(ent, bouncestop);
2684 bouncestop = 60.0f / 800.0f;
2686 ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2687 ent_gravity = PRVM_serveredictfloat(ent, gravity);
2690 // LordHavoc: fixed grenades not bouncing when fired down a slope
2691 if (sv_gameplayfix_grenadebouncedownslopes.integer)
2692 d = fabs(DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity)));
2694 d = PRVM_serveredictvector(ent, velocity)[2];
2695 if (trace.plane.normal[2] > 0.7 && d < sv_gravity.value * bouncestop * ent_gravity)
2697 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2698 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2699 VectorClear(PRVM_serveredictvector(ent, velocity));
2700 VectorClear(PRVM_serveredictvector(ent, avelocity));
2705 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2706 if (!sv_gameplayfix_slidemoveprojectiles.integer)
2711 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
2712 if (trace.plane.normal[2] > 0.7)
2714 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2715 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2716 if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
2717 ent->priv.server->suspendedinairflag = true;
2718 VectorClear (PRVM_serveredictvector(ent, velocity));
2719 VectorClear (PRVM_serveredictvector(ent, avelocity));
2722 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2728 // check for in water
2729 SV_CheckWaterTransition (ent);
2733 ===============================================================================
2737 ===============================================================================
2744 Monsters freefall when they don't have a ground entity, otherwise
2745 all movement is done with discrete steps.
2747 This is also used for objects that have become still on the ground, but
2748 will fall if the floor is pulled out from under them.
2751 void SV_Physics_Step (prvm_edict_t *ent)
2753 int flags = (int)PRVM_serveredictfloat(ent, flags);
2756 // Backup Velocity in the event that movetypesteplandevent is called,
2757 // to provide a parameter with the entity's velocity at impact.
2758 vec3_t backupVelocity;
2759 VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2760 // don't fall at all if fly/swim
2761 if (!(flags & (FL_FLY | FL_SWIM)))
2763 if (flags & FL_ONGROUND)
2765 // freefall if onground and moving upward
2766 // freefall if not standing on a world surface (it may be a lift or trap door)
2767 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2769 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2770 SV_CheckVelocity(ent);
2771 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2773 SV_LinkEdict_TouchAreaGrid(ent);
2774 ent->priv.server->waterposition_forceupdate = true;
2779 // freefall if not onground
2780 int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2782 SV_CheckVelocity(ent);
2783 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2785 SV_LinkEdict_TouchAreaGrid(ent);
2788 if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2790 // DRESK - Check for Entity Land Event Function
2791 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2792 { // Valid Function; Execute
2793 // Prepare Parameters
2794 // Assign Velocity at Impact
2795 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2796 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2797 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2799 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2800 // Execute VM Function
2801 PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2804 // Check for Engine Landing Sound
2805 if(sv_sound_land.string)
2806 SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false, 1.0f);
2808 ent->priv.server->waterposition_forceupdate = true;
2813 if (!SV_RunThink(ent))
2816 if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2818 ent->priv.server->waterposition_forceupdate = false;
2819 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2820 SV_CheckWaterTransition(ent);
2824 //============================================================================
2826 static void SV_Physics_Entity (prvm_edict_t *ent)
2828 // don't run think/move on newly spawned projectiles as it messes up
2829 // movement interpolation and rocket trails, and is inconsistent with
2830 // respect to entities spawned in the same frame
2831 // (if an ent spawns a higher numbered ent, it moves in the same frame,
2832 // but if it spawns a lower numbered ent, it doesn't - this never moves
2833 // ents in the first frame regardless)
2834 qboolean runmove = ent->priv.server->move;
2835 ent->priv.server->move = true;
2836 if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2838 switch ((int) PRVM_serveredictfloat(ent, movetype))
2841 case MOVETYPE_FAKEPUSH:
2842 SV_Physics_Pusher (ent);
2845 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2846 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2849 case MOVETYPE_FOLLOW:
2850 SV_Physics_Follow (ent);
2852 case MOVETYPE_NOCLIP:
2853 if (SV_RunThink(ent))
2856 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2857 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2862 SV_Physics_Step (ent);
2865 if (SV_RunThink (ent))
2869 case MOVETYPE_BOUNCE:
2870 case MOVETYPE_BOUNCEMISSILE:
2871 case MOVETYPE_FLYMISSILE:
2873 case MOVETYPE_FLY_WORLDONLY:
2875 if (SV_RunThink (ent))
2876 SV_Physics_Toss (ent);
2878 case MOVETYPE_PHYSICS:
2879 if (SV_RunThink(ent))
2882 SV_LinkEdict_TouchAreaGrid(ent);
2886 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2891 void SV_Physics_ClientMove(void)
2894 ent = host_client->edict;
2896 // call player physics, this needs the proper frametime
2897 PRVM_serverglobalfloat(frametime) = sv.frametime;
2900 // call standard client pre-think, with frametime = 0
2901 PRVM_serverglobalfloat(time) = sv.time;
2902 PRVM_serverglobalfloat(frametime) = 0;
2903 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2904 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2905 PRVM_serverglobalfloat(frametime) = sv.frametime;
2907 // make sure the velocity is sane (not a NaN)
2908 SV_CheckVelocity(ent);
2910 // perform MOVETYPE_WALK behavior
2913 // call standard player post-think, with frametime = 0
2914 PRVM_serverglobalfloat(time) = sv.time;
2915 PRVM_serverglobalfloat(frametime) = 0;
2916 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2917 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2918 PRVM_serverglobalfloat(frametime) = sv.frametime;
2920 if(PRVM_serveredictfloat(ent, fixangle))
2922 // angle fixing was requested by physics code...
2923 // so store the current angles for later use
2924 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2925 host_client->fixangle_angles_set = TRUE;
2927 // and clear fixangle for the next frame
2928 PRVM_serveredictfloat(ent, fixangle) = 0;
2932 static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
2934 // don't do physics on disconnected clients, FrikBot relies on this
2935 if (!host_client->spawned)
2938 // make sure the velocity is sane (not a NaN)
2939 SV_CheckVelocity(ent);
2941 // don't run physics here if running asynchronously
2942 if (host_client->clmovement_inputtimeout <= 0)
2945 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
2948 // make sure the velocity is still sane (not a NaN)
2949 SV_CheckVelocity(ent);
2951 // call standard client pre-think
2952 PRVM_serverglobalfloat(time) = sv.time;
2953 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2954 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2956 // make sure the velocity is still sane (not a NaN)
2957 SV_CheckVelocity(ent);
2960 static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
2962 // don't do physics on disconnected clients, FrikBot relies on this
2963 if (!host_client->spawned)
2966 // make sure the velocity is sane (not a NaN)
2967 SV_CheckVelocity(ent);
2969 // call standard player post-think
2970 PRVM_serverglobalfloat(time) = sv.time;
2971 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2972 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2974 // make sure the velocity is still sane (not a NaN)
2975 SV_CheckVelocity(ent);
2977 if(PRVM_serveredictfloat(ent, fixangle))
2979 // angle fixing was requested by physics code...
2980 // so store the current angles for later use
2981 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2982 host_client->fixangle_angles_set = TRUE;
2984 // and clear fixangle for the next frame
2985 PRVM_serveredictfloat(ent, fixangle) = 0;
2988 // decrement the countdown variable used to decide when to go back to
2989 // synchronous physics
2990 if (host_client->clmovement_inputtimeout > sv.frametime)
2991 host_client->clmovement_inputtimeout -= sv.frametime;
2993 host_client->clmovement_inputtimeout = 0;
2996 static void SV_Physics_ClientEntity(prvm_edict_t *ent)
2998 // don't do physics on disconnected clients, FrikBot relies on this
2999 if (!host_client->spawned)
3001 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
3005 // make sure the velocity is sane (not a NaN)
3006 SV_CheckVelocity(ent);
3008 switch ((int) PRVM_serveredictfloat(ent, movetype))
3011 case MOVETYPE_FAKEPUSH:
3012 SV_Physics_Pusher (ent);
3015 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
3016 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
3019 case MOVETYPE_FOLLOW:
3020 SV_Physics_Follow (ent);
3022 case MOVETYPE_NOCLIP:
3025 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
3026 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
3029 SV_Physics_Step (ent);
3033 // don't run physics here if running asynchronously
3034 if (host_client->clmovement_inputtimeout <= 0)
3038 case MOVETYPE_BOUNCE:
3039 case MOVETYPE_BOUNCEMISSILE:
3040 case MOVETYPE_FLYMISSILE:
3043 SV_Physics_Toss (ent);
3046 case MOVETYPE_FLY_WORLDONLY:
3050 case MOVETYPE_PHYSICS:
3054 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
3058 SV_CheckVelocity (ent);
3061 SV_LinkEdict_TouchAreaGrid(ent);
3063 SV_CheckVelocity (ent);
3072 void SV_Physics (void)
3077 // let the progs know that a new frame has started
3078 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3079 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3080 PRVM_serverglobalfloat(time) = sv.time;
3081 PRVM_serverglobalfloat(frametime) = sv.frametime;
3082 PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
3084 // run physics engine
3085 World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
3088 // treat each object in turn
3091 // if force_retouch, relink all the entities
3092 if (PRVM_serverglobalfloat(force_retouch) > 0)
3093 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3094 if (!ent->priv.server->free)
3095 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
3097 if (sv_gameplayfix_consistentplayerprethink.integer)
3099 // run physics on the client entities in 3 stages
3100 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3101 if (!ent->priv.server->free)
3102 SV_Physics_ClientEntity_PreThink(ent);
3104 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3105 if (!ent->priv.server->free)
3106 SV_Physics_ClientEntity(ent);
3108 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3109 if (!ent->priv.server->free)
3110 SV_Physics_ClientEntity_PostThink(ent);
3114 // run physics on the client entities
3115 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3117 if (!ent->priv.server->free)
3119 SV_Physics_ClientEntity_PreThink(ent);
3120 SV_Physics_ClientEntity(ent);
3121 SV_Physics_ClientEntity_PostThink(ent);
3126 // run physics on all the non-client entities
3127 if (!sv_freezenonclients.integer)
3129 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3130 if (!ent->priv.server->free)
3131 SV_Physics_Entity(ent);
3132 // make a second pass to see if any ents spawned this frame and make
3133 // sure they run their move/think
3134 if (sv_gameplayfix_delayprojectiles.integer < 0)
3135 for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3136 if (!ent->priv.server->move && !ent->priv.server->free)
3137 SV_Physics_Entity(ent);
3140 if (PRVM_serverglobalfloat(force_retouch) > 0)
3141 PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
3143 // LordHavoc: endframe support
3144 if (PRVM_serverfunction(EndFrame))
3146 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3147 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3148 PRVM_serverglobalfloat(time) = sv.time;
3149 PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3152 // decrement prog->num_edicts if the highest number entities died
3153 for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3155 if (!sv_freezenonclients.integer)
3156 sv.time += sv.frametime;