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 = World_EntitiesInBox(&sv.world, 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 = World_EntitiesInBox(&sv.world, 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 = World_EntitiesInBox(&sv.world, 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 = World_EntitiesInBox(&sv.world, 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 void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
704 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch);
705 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent);
706 PRVM_serverglobalfloat(time) = sv.time;
707 PRVM_serverglobalfloat(trace_allsolid) = false;
708 PRVM_serverglobalfloat(trace_startsolid) = false;
709 PRVM_serverglobalfloat(trace_fraction) = 1;
710 PRVM_serverglobalfloat(trace_inwater) = false;
711 PRVM_serverglobalfloat(trace_inopen) = true;
712 VectorCopy (PRVM_serveredictvector(touch, origin), PRVM_serverglobalvector(trace_endpos));
713 VectorSet (PRVM_serverglobalvector(trace_plane_normal), 0, 0, 1);
714 PRVM_serverglobalfloat(trace_plane_dist) = 0;
715 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(ent);
716 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
717 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
718 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
719 PRVM_serverglobalstring(trace_dphittexturename) = 0;
720 PRVM_ExecuteProgram (PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
723 void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
725 int i, numtouchedicts, old_self, old_other;
727 static prvm_edict_t *touchedicts[MAX_EDICTS];
729 if (ent == prog->edicts)
730 return; // don't add the world
732 if (ent->priv.server->free)
735 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
738 // build a list of edicts to touch, because the link loop can be corrupted
739 // by IncreaseEdicts called during touch functions
740 numtouchedicts = World_EntitiesInBox(&sv.world, ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
741 if (numtouchedicts > MAX_EDICTS)
743 // this never happens
744 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
745 numtouchedicts = MAX_EDICTS;
748 old_self = PRVM_serverglobaledict(self);
749 old_other = PRVM_serverglobaledict(other);
750 for (i = 0;i < numtouchedicts;i++)
752 touch = touchedicts[i];
753 if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch))
755 SV_LinkEdict_TouchAreaGrid_Call(touch, ent);
758 PRVM_serverglobaledict(self) = old_self;
759 PRVM_serverglobaledict(other) = old_other;
762 static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
766 Matrix4x4_CreateFromQuakeEntity(&m, 0, 0, 0, angles[PITCH], angles[YAW], angles[ROLL], 1.0);
768 v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
769 VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs);
770 v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
771 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];
772 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];
773 v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
774 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];
775 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];
776 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
777 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];
778 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];
779 v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
780 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];
781 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];
782 v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
783 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];
784 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];
785 v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
786 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];
787 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];
788 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
789 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];
790 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];
799 void SV_LinkEdict (prvm_edict_t *ent)
805 if (ent == prog->edicts)
806 return; // don't add the world
808 if (ent->priv.server->free)
811 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
812 if (modelindex < 0 || modelindex >= MAX_MODELS)
814 Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
817 model = SV_GetModelByIndex(modelindex);
819 VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
820 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
821 VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
825 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_PHYSICS)
827 // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
828 // TODO special handling for spheres?
829 RotateBBox(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, angles), mins, maxs);
830 VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins);
831 VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs);
833 else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
837 if (!model->TraceBox)
838 Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
840 if (PRVM_serveredictvector(ent, angles)[0] || PRVM_serveredictvector(ent, angles)[2] || PRVM_serveredictvector(ent, avelocity)[0] || PRVM_serveredictvector(ent, avelocity)[2])
842 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins);
843 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs);
845 else if (PRVM_serveredictvector(ent, angles)[1] || PRVM_serveredictvector(ent, avelocity)[1])
847 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmins, mins);
848 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmaxs, maxs);
852 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins);
853 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs);
858 // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
859 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
860 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
865 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
866 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
870 // to make items easier to pick up and allow them to be grabbed off
871 // of shelves, the abs sizes are expanded
873 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
884 // because movement is clipped an epsilon away from an actual edge,
885 // we must fully check even when bounding boxes don't quite touch
894 VectorCopy(mins, PRVM_serveredictvector(ent, absmin));
895 VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
897 World_LinkEdict(&sv.world, ent, mins, maxs);
901 ===============================================================================
905 ===============================================================================
910 SV_TestEntityPosition
912 returns true if the entity is in solid currently
915 static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
920 contents = SV_GenericHitSuperContentsMask(ent);
921 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
922 trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), MOVE_NOMONSTERS, ent, contents);
923 if (trace.startsupercontents & contents)
927 if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs)))
929 // q1bsp/hlbsp use hulls and if the entity does not exactly match
930 // a hull size it is incorrectly tested, so this code tries to
931 // 'fix' it slightly...
932 // FIXME: this breaks entities larger than the hull size
935 VectorAdd(org, PRVM_serveredictvector(ent, mins), m1);
936 VectorAdd(org, PRVM_serveredictvector(ent, maxs), m2);
937 VectorSubtract(m2, m1, s);
938 #define EPSILON (1.0f / 32.0f)
939 if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
940 if (s[1] >= EPSILON*2) {m1[1] += EPSILON;m2[1] -= EPSILON;}
941 if (s[2] >= EPSILON*2) {m1[2] += EPSILON;m2[2] -= EPSILON;}
942 for (i = 0;i < 8;i++)
944 v[0] = (i & 1) ? m2[0] : m1[0];
945 v[1] = (i & 2) ? m2[1] : m1[1];
946 v[2] = (i & 4) ? m2[2] : m1[2];
947 if (SV_PointSuperContents(v) & contents)
952 // if the trace found a better position for the entity, move it there
953 if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001)
956 // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
957 VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
959 // verify if the endpos is REALLY outside solid
960 VectorCopy(trace.endpos, org);
961 trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), org, MOVE_NOMONSTERS, ent, contents);
963 Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
965 VectorCopy(org, PRVM_serveredictvector(ent, origin));
976 void SV_CheckAllEnts (void)
981 // see if any solid entities are inside the final position
982 check = PRVM_NEXT_EDICT(prog->edicts);
983 for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check))
985 if (check->priv.server->free)
987 if (PRVM_serveredictfloat(check, movetype) == MOVETYPE_PUSH
988 || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NONE
989 || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FOLLOW
990 || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NOCLIP)
993 if (SV_TestEntityPosition (check, vec3_origin))
994 Con_Print("entity in invalid position\n");
998 // DRESK - Support for Entity Contents Transition Event
1001 SV_CheckContentsTransition
1003 returns true if entity had a valid contentstransition function call
1006 int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
1008 int bValidFunctionCall;
1010 // Default Valid Function Call to False
1011 bValidFunctionCall = false;
1013 if(PRVM_serveredictfloat(ent, watertype) != nContents)
1014 { // Changed Contents
1015 // Acquire Contents Transition Function from QC
1016 if(PRVM_serveredictfunction(ent, contentstransition))
1017 { // Valid Function; Execute
1018 // Assign Valid Function
1019 bValidFunctionCall = true;
1020 // Prepare Parameters (Original Contents, New Contents)
1021 // Original Contents
1022 PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
1024 PRVM_G_FLOAT(OFS_PARM1) = nContents;
1026 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1027 // Execute VM Function
1028 PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
1032 // Return if Function Call was Valid
1033 return bValidFunctionCall;
1042 void SV_CheckVelocity (prvm_edict_t *ent)
1050 for (i=0 ; i<3 ; i++)
1052 if (IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
1054 Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1055 PRVM_serveredictvector(ent, velocity)[i] = 0;
1057 if (IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
1059 Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1060 PRVM_serveredictvector(ent, origin)[i] = 0;
1064 // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
1065 // player_run/player_stand1 does not horribly malfunction if the
1066 // velocity becomes a denormalized float
1067 if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001)
1068 VectorClear(PRVM_serveredictvector(ent, velocity));
1070 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
1071 wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity));
1072 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
1074 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
1075 PRVM_serveredictvector(ent, velocity)[0] *= wishspeed;
1076 PRVM_serveredictvector(ent, velocity)[1] *= wishspeed;
1077 PRVM_serveredictvector(ent, velocity)[2] *= wishspeed;
1085 Runs thinking code if time. There is some play in the exact time the think
1086 function will be called, because it is called before any movement is done
1087 in a frame. Not used for pushmove objects, because they must be exact.
1088 Returns false if the entity removed itself.
1091 qboolean SV_RunThink (prvm_edict_t *ent)
1095 // don't let things stay in the past.
1096 // it is possible to start that way by a trigger with a local time.
1097 if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime)
1100 for (iterations = 0;iterations < 128 && !ent->priv.server->free;iterations++)
1102 PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink));
1103 PRVM_serveredictfloat(ent, nextthink) = 0;
1104 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1105 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1106 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1107 // mods often set nextthink to time to cause a think every frame,
1108 // we don't want to loop in that case, so exit if the new nextthink is
1109 // <= the time the qc was told, also exit if it is past the end of the
1111 if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
1114 return !ent->priv.server->free;
1121 Two entities have touched, so run their touch functions
1124 extern void VM_SetTraceGlobals(const trace_t *trace);
1125 extern sizebuf_t vm_tempstringsbuf;
1126 void SV_Impact (prvm_edict_t *e1, trace_t *trace)
1128 int restorevm_tempstringsbuf_cursize;
1129 int old_self, old_other;
1130 prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
1132 old_self = PRVM_serverglobaledict(self);
1133 old_other = PRVM_serverglobaledict(other);
1134 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1136 VM_SetTraceGlobals(trace);
1138 PRVM_serverglobalfloat(time) = sv.time;
1139 if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
1141 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e1);
1142 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e2);
1143 PRVM_ExecuteProgram (PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
1146 if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
1148 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2);
1149 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1);
1150 VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos));
1151 VectorNegate(trace->plane.normal, PRVM_serverglobalvector(trace_plane_normal));
1152 PRVM_serverglobalfloat(trace_plane_dist) = -trace->plane.dist;
1153 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(e1);
1154 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
1155 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
1156 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
1157 PRVM_serverglobalstring(trace_dphittexturename) = 0;
1158 PRVM_ExecuteProgram (PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
1161 PRVM_serverglobaledict(self) = old_self;
1162 PRVM_serverglobaledict(other) = old_other;
1163 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1171 Slide off of the impacting object
1172 returns the blocked flags (1 = floor, 2 = step / wall)
1175 #define STOP_EPSILON 0.1
1176 void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
1181 backoff = -DotProduct (in, normal) * overbounce;
1182 VectorMA(in, backoff, normal, out);
1184 for (i = 0;i < 3;i++)
1185 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
1194 The basic solid body movement clip that slides along multiple planes
1195 Returns the clipflags if the velocity was modified (hit something solid)
1199 8 = teleported by touch method
1200 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
1203 static float SV_Gravity (prvm_edict_t *ent);
1204 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
1205 #define MAX_CLIP_PLANES 5
1206 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask, float stepheight)
1208 int blocked, bumpcount;
1209 int i, j, numplanes;
1210 float d, time_left, gravity;
1211 vec3_t dir, push, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
1220 if(sv_gameplayfix_nogravityonground.integer)
1221 if((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
1222 applygravity = false;
1226 if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
1228 gravity = SV_Gravity(ent) * 0.5f;
1229 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1233 applygravity = false;
1234 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
1238 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1239 VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
1242 for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
1244 if (!PRVM_serveredictvector(ent, velocity)[0] && !PRVM_serveredictvector(ent, velocity)[1] && !PRVM_serveredictvector(ent, velocity)[2])
1247 VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
1248 if(!SV_PushEntity(&trace, ent, push, false, false))
1250 // we got teleported by a touch function
1251 // let's abort the move
1256 if (trace.fraction == 1)
1258 if (trace.plane.normal[2])
1260 if (trace.plane.normal[2] > 0.7)
1267 Con_Printf ("SV_FlyMove: !trace.ent");
1268 trace.ent = prog->edicts;
1271 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1272 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1275 else if (stepheight)
1277 // step - handle it immediately
1283 //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1284 VectorSet(steppush, 0, 0, stepheight);
1285 VectorCopy(PRVM_serveredictvector(ent, origin), org);
1286 if(!SV_PushEntity(&steptrace, ent, steppush, false, false))
1291 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1292 if(!SV_PushEntity(&steptrace2, ent, push, false, false))
1297 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1298 VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
1299 if(!SV_PushEntity(&steptrace3, ent, steppush, false, false))
1304 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1305 // accept the new position if it made some progress...
1306 if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
1308 //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]);
1310 VectorCopy(PRVM_serveredictvector(ent, origin), trace.endpos);
1311 time_left *= 1 - trace.fraction;
1317 //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]);
1318 VectorCopy(org, PRVM_serveredictvector(ent, origin));
1323 // step - return it to caller
1325 // save the trace for player extrafriction
1327 VectorCopy(trace.plane.normal, stepnormal);
1329 if (trace.fraction >= 0.001)
1331 // actually covered some distance
1332 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1336 time_left *= 1 - trace.fraction;
1338 // clipped to another plane
1339 if (numplanes >= MAX_CLIP_PLANES)
1341 // this shouldn't really happen
1342 VectorClear(PRVM_serveredictvector(ent, velocity));
1348 for (i = 0;i < numplanes;i++)
1349 if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
1353 VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity));
1358 VectorCopy(trace.plane.normal, planes[numplanes]);
1361 // modify original_velocity so it parallels all of the clip planes
1362 for (i = 0;i < numplanes;i++)
1364 ClipVelocity(original_velocity, planes[i], new_velocity, 1);
1365 for (j = 0;j < numplanes;j++)
1370 if (DotProduct(new_velocity, planes[j]) < 0)
1380 // go along this plane
1381 VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity));
1385 // go along the crease
1388 VectorClear(PRVM_serveredictvector(ent, velocity));
1392 CrossProduct(planes[0], planes[1], dir);
1393 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
1394 VectorNormalize(dir);
1395 d = DotProduct(dir, PRVM_serveredictvector(ent, velocity));
1396 VectorScale(dir, d, PRVM_serveredictvector(ent, velocity));
1399 // if current velocity is against the original velocity,
1400 // stop dead to avoid tiny occilations in sloping corners
1401 if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0)
1403 VectorClear(PRVM_serveredictvector(ent, velocity));
1408 //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]);
1411 if ((blocked & 1) == 0 && bumpcount > 1)
1413 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
1414 // flag ONGROUND if there's ground under it
1415 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask);
1419 // LordHavoc: this came from QW and allows you to get out of water more easily
1420 if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
1421 VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
1422 if (applygravity && !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
1423 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1433 static float SV_Gravity (prvm_edict_t *ent)
1437 ent_gravity = PRVM_serveredictfloat(ent, gravity);
1440 return ent_gravity * sv_gravity.value * sv.frametime;
1445 ===============================================================================
1449 ===============================================================================
1452 static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
1457 vec3_t stuckmins, stuckmaxs;
1458 vec3_t goodmins, goodmaxs;
1462 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1463 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1464 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1465 VectorCopy(pivot, goodmins);
1466 VectorCopy(pivot, goodmaxs);
1467 for (bump = 0;bump < 6;bump++)
1469 int coord = 2-(bump >> 1);
1470 //int coord = (bump >> 1);
1471 int dir = (bump & 1);
1474 for(subbump = 0; ; ++subbump)
1476 VectorCopy(stuckorigin, testorigin);
1480 testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord];
1485 testorigin[coord] += stuckmins[coord] - goodmins[coord];
1488 stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1489 if (stucktrace.bmodelstartsolid)
1491 // BAD BAD, can't fix that
1495 if (stucktrace.fraction >= 1)
1500 // BAD BAD, can't fix that
1504 // we hit something... let's move out of it
1505 VectorSubtract(stucktrace.endpos, testorigin, move);
1506 nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant
1507 VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin);
1511 Con_Printf("subbump: %d\n", subbump);
1517 goodmaxs[coord] = stuckmaxs[coord];
1522 goodmins[coord] = stuckmins[coord];
1527 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1532 static qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
1537 vec3_t stuckmins, stuckmaxs;
1539 vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
1540 if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
1541 separation = 0.0f; // when using hulls, it can not be enlarged
1542 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1543 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1544 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1545 stuckmins[0] -= separation;
1546 stuckmins[1] -= separation;
1547 stuckmins[2] -= separation;
1548 stuckmaxs[0] += separation;
1549 stuckmaxs[1] += separation;
1550 stuckmaxs[2] += separation;
1551 for (bump = 0;bump < 10;bump++)
1553 stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1554 if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
1556 // found a good location, use it
1557 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1560 nudge = -stucktrace.startdepth;
1561 VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
1570 Does not change the entities velocity at all
1571 The trace struct is filled with the trace that has been done.
1572 Returns true if the push did not result in the entity being teleported by QC code.
1575 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
1581 vec3_t original, original_velocity;
1585 solid = (int)PRVM_serveredictfloat(ent, solid);
1586 movetype = (int)PRVM_serveredictfloat(ent, movetype);
1587 VectorCopy(PRVM_serveredictvector(ent, mins), mins);
1588 VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
1590 // move start position out of solids
1591 if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
1593 SV_NudgeOutOfSolid(ent);
1596 VectorCopy(PRVM_serveredictvector(ent, origin), start);
1597 VectorAdd(start, push, end);
1599 if (movetype == MOVETYPE_FLYMISSILE)
1600 type = MOVE_MISSILE;
1601 else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
1602 type = MOVE_NOMONSTERS; // only clip against bmodels
1606 *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
1607 if (trace->bmodelstartsolid && failonbmodelstartsolid)
1610 VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
1612 VectorCopy(PRVM_serveredictvector(ent, origin), original);
1613 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1618 if(!trace->startsolid)
1619 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)
1621 Con_Printf("something eeeeevil happened\n");
1626 SV_LinkEdict_TouchAreaGrid(ent);
1628 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))))
1629 SV_Impact (ent, trace);
1631 return VectorCompare(PRVM_serveredictvector(ent, origin), original) && VectorCompare(PRVM_serveredictvector(ent, velocity), original_velocity);
1641 void SV_PushMove (prvm_edict_t *pusher, float movetime)
1644 int pusherowner, pusherprog;
1647 float savesolid, movetime2, pushltime;
1648 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org;
1650 int numcheckentities;
1651 static prvm_edict_t *checkentities[MAX_EDICTS];
1652 dp_model_t *pushermodel;
1653 trace_t trace, trace2;
1654 matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
1655 static unsigned short moved_edicts[MAX_EDICTS];
1658 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])
1660 PRVM_serveredictfloat(pusher, ltime) += movetime;
1664 switch ((int) PRVM_serveredictfloat(pusher, solid))
1666 // LordHavoc: valid pusher types
1669 case SOLID_SLIDEBOX:
1670 case SOLID_CORPSE: // LordHavoc: this would be weird...
1672 // LordHavoc: no collisions
1675 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1676 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1677 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1678 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1679 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1680 PRVM_serveredictfloat(pusher, ltime) += movetime;
1681 SV_LinkEdict(pusher);
1684 Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
1687 index = (int) PRVM_serveredictfloat(pusher, modelindex);
1688 if (index < 1 || index >= MAX_MODELS)
1690 Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
1693 pushermodel = SV_GetModelByIndex(index);
1694 pusherowner = PRVM_serveredictedict(pusher, owner);
1695 pusherprog = PRVM_EDICT_TO_PROG(pusher);
1697 rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0;
1699 movetime2 = movetime;
1700 VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
1701 VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
1702 if (moveangle[0] || moveangle[2])
1704 for (i = 0;i < 3;i++)
1708 mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1709 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1713 mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1714 maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1718 else if (moveangle[1])
1720 for (i = 0;i < 3;i++)
1724 mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1725 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1729 mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1730 maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1736 for (i = 0;i < 3;i++)
1740 mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1741 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1745 mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1746 maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1751 VectorNegate (moveangle, a);
1752 AngleVectorsFLU (a, forward, left, up);
1754 VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
1755 VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
1756 pushltime = PRVM_serveredictfloat(pusher, ltime);
1758 // move the pusher to its final position
1760 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1761 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1762 PRVM_serveredictfloat(pusher, ltime) += movetime;
1763 SV_LinkEdict(pusher);
1765 pushermodel = SV_GetModelFromEdict(pusher);
1766 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);
1767 Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
1769 savesolid = PRVM_serveredictfloat(pusher, solid);
1771 // see if any solid entities are inside the final position
1774 numcheckentities = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, checkentities);
1775 for (e = 0;e < numcheckentities;e++)
1777 prvm_edict_t *check = checkentities[e];
1778 int movetype = (int)PRVM_serveredictfloat(check, movetype);
1783 case MOVETYPE_FOLLOW:
1784 case MOVETYPE_NOCLIP:
1785 case MOVETYPE_FAKEPUSH:
1791 if (PRVM_serveredictedict(check, owner) == pusherprog)
1794 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1797 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1799 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1800 check->priv.server->waterposition_forceupdate = true;
1802 checkcontents = SV_GenericHitSuperContentsMask(check);
1804 // if the entity is standing on the pusher, it will definitely be moved
1805 // if the entity is not standing on the pusher, but is in the pusher's
1806 // final position, move it
1807 if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
1809 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);
1810 //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1811 if (!trace.startsolid)
1813 //Con_Printf("- not in solid\n");
1818 VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot);
1819 //VectorClear(pivot);
1824 VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org);
1825 VectorAdd (org, pivot, org);
1826 org2[0] = DotProduct (org, forward);
1827 org2[1] = DotProduct (org, left);
1828 org2[2] = DotProduct (org, up);
1829 VectorSubtract (org2, org, move);
1830 VectorAdd (move, move1, move);
1833 VectorCopy (move1, move);
1835 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1837 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1838 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1839 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1841 // physics objects need better collisions than this code can do
1842 if (movetype == MOVETYPE_PHYSICS)
1844 VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
1845 SV_LinkEdict(check);
1846 SV_LinkEdict_TouchAreaGrid(check);
1850 // try moving the contacted entity
1851 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1852 if(!SV_PushEntity (&trace, check, move, true, true))
1854 // entity "check" got teleported
1855 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1856 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1857 continue; // pushed enough
1859 // FIXME: turn players specially
1860 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1861 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1862 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1864 // this trace.fraction < 1 check causes items to fall off of pushers
1865 // if they pass under or through a wall
1866 // the groundentity check causes items to fall off of ledges
1867 if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
1868 PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1870 // if it is still inside the pusher, block
1871 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);
1872 if (trace.startsolid)
1875 if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
1877 // hack to invoke all necessary movement triggers
1879 if(!SV_PushEntity(&trace2, check, move2, true, true))
1881 // entity "check" got teleported
1888 // still inside pusher, so it's really blocked
1891 if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1893 if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER)
1896 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1897 VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs));
1901 VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1902 VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1903 PRVM_serveredictfloat(pusher, ltime) = pushltime;
1904 SV_LinkEdict(pusher);
1906 // move back any entities we already moved
1907 for (i = 0;i < num_moved;i++)
1909 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1910 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1911 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
1915 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
1916 if (PRVM_serveredictfunction(pusher, blocked))
1918 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
1919 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
1920 PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
1925 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1926 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1927 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1936 void SV_Physics_Pusher (prvm_edict_t *ent)
1938 float thinktime, oldltime, movetime;
1940 oldltime = PRVM_serveredictfloat(ent, ltime);
1942 thinktime = PRVM_serveredictfloat(ent, nextthink);
1943 if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
1945 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
1950 movetime = sv.frametime;
1953 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
1954 SV_PushMove (ent, movetime);
1956 if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
1958 PRVM_serveredictfloat(ent, nextthink) = 0;
1959 PRVM_serverglobalfloat(time) = sv.time;
1960 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1961 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1962 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1968 ===============================================================================
1972 ===============================================================================
1975 static float unstickoffsets[] =
1977 // poutting -/+z changes first as they are least weird
1992 typedef enum unstickresult_e
2000 unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
2004 // if not stuck in a bmodel, just return
2005 if (!SV_TestEntityPosition(ent, vec3_origin))
2006 return UNSTICK_GOOD;
2008 for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
2010 if (!SV_TestEntityPosition(ent, unstickoffsets + i))
2012 VectorCopy(unstickoffsets + i, offset);
2014 //SV_LinkEdict_TouchAreaGrid(ent);
2015 return UNSTICK_UNSTUCK;
2019 maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
2020 // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
2022 for(i = 2; i <= maxunstick; ++i)
2024 VectorClear(offset);
2026 if (!SV_TestEntityPosition(ent, offset))
2029 //SV_LinkEdict_TouchAreaGrid(ent);
2030 return UNSTICK_UNSTUCK;
2033 if (!SV_TestEntityPosition(ent, offset))
2036 //SV_LinkEdict_TouchAreaGrid(ent);
2037 return UNSTICK_UNSTUCK;
2041 return UNSTICK_STUCK;
2044 qboolean SV_UnstickEntity (prvm_edict_t *ent)
2047 switch(SV_UnstickEntityReturnOffset(ent, offset))
2051 case UNSTICK_UNSTUCK:
2052 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]);
2055 if (developer_extra.integer)
2056 Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2059 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2068 This is a big hack to try and fix the rare case of getting stuck in the world
2072 void SV_CheckStuck (prvm_edict_t *ent)
2076 switch(SV_UnstickEntityReturnOffset(ent, offset))
2079 VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
2081 case UNSTICK_UNSTUCK:
2082 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]);
2085 VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
2086 if (!SV_TestEntityPosition(ent, offset))
2088 Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2090 //SV_LinkEdict_TouchAreaGrid(ent);
2093 Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2096 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2106 qboolean SV_CheckWater (prvm_edict_t *ent)
2109 int nNativeContents;
2112 point[0] = PRVM_serveredictvector(ent, origin)[0];
2113 point[1] = PRVM_serveredictvector(ent, origin)[1];
2114 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2116 // DRESK - Support for Entity Contents Transition Event
2117 // NOTE: Some logic needed to be slightly re-ordered
2118 // to not affect performance and allow for the feature.
2120 // Acquire Super Contents Prior to Resets
2121 cont = SV_PointSuperContents(point);
2122 // Acquire Native Contents Here
2123 nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
2125 // DRESK - Support for Entity Contents Transition Event
2126 if(PRVM_serveredictfloat(ent, watertype))
2127 // Entity did NOT Spawn; Check
2128 SV_CheckContentsTransition(ent, nNativeContents);
2131 PRVM_serveredictfloat(ent, waterlevel) = 0;
2132 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2133 cont = SV_PointSuperContents(point);
2134 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2136 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2137 PRVM_serveredictfloat(ent, waterlevel) = 1;
2138 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2139 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2141 PRVM_serveredictfloat(ent, waterlevel) = 2;
2142 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2143 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2144 PRVM_serveredictfloat(ent, waterlevel) = 3;
2148 return PRVM_serveredictfloat(ent, waterlevel) > 1;
2157 void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2160 vec3_t forward, into, side;
2162 AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
2163 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2165 // cut the tangential velocity
2166 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2167 VectorScale (stepnormal, i, into);
2168 VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
2169 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2170 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2176 =====================
2179 Player has come to a dead stop, possibly due to the problem with limited
2180 float precision at some angle joins in the BSP hull.
2182 Try fixing by pushing one pixel in each direction.
2184 This is a hack, but in the interest of good gameplay...
2185 ======================
2187 int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2192 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
2195 for (i=0 ; i<8 ; i++)
2197 // try pushing a little in an axial direction
2200 case 0: dir[0] = 2; dir[1] = 0; break;
2201 case 1: dir[0] = 0; dir[1] = 2; break;
2202 case 2: dir[0] = -2; dir[1] = 0; break;
2203 case 3: dir[0] = 0; dir[1] = -2; break;
2204 case 4: dir[0] = 2; dir[1] = 2; break;
2205 case 5: dir[0] = -2; dir[1] = 2; break;
2206 case 6: dir[0] = 2; dir[1] = -2; break;
2207 case 7: dir[0] = -2; dir[1] = -2; break;
2210 SV_PushEntity (&trace, ent, dir, false, true);
2212 // retry the original move
2213 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2214 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2215 PRVM_serveredictvector(ent, velocity)[2] = 0;
2216 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
2218 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2219 || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2221 Con_DPrint("TryUnstick - success.\n");
2225 // go back to the original pos and try again
2226 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
2230 VectorClear (PRVM_serveredictvector(ent, velocity));
2231 Con_DPrint("TryUnstick - failure.\n");
2237 =====================
2240 Only used by players
2241 ======================
2243 void SV_WalkMove (prvm_edict_t *ent)
2247 //int originalmove_clip;
2248 int originalmove_flags;
2249 int originalmove_groundentity;
2250 int hitsupercontentsmask;
2252 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
2253 trace_t downtrace, trace;
2254 qboolean applygravity;
2256 // if frametime is 0 (due to client sending the same timestamp twice),
2258 if (sv.frametime <= 0)
2261 SV_CheckStuck (ent);
2263 applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2265 hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2267 SV_CheckVelocity(ent);
2269 // do a regular slide move unless it looks like you ran into a step
2270 oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2272 VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2273 VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2275 clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2277 if(sv_gameplayfix_downtracesupportsongroundflag.integer)
2280 // only try this if there was no floor in the way in the trace (no,
2281 // this check seems to be not REALLY necessary, because if clip & 1,
2282 // our trace will hit that thing too)
2283 VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
2284 VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
2285 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
2286 type = MOVE_MISSILE;
2287 else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
2288 type = MOVE_NOMONSTERS; // only clip against bmodels
2291 trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
2292 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2293 clip |= 1; // but we HAVE found a floor
2296 // if the move did not hit the ground at any point, we're not on ground
2298 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2300 SV_CheckVelocity(ent);
2302 SV_LinkEdict_TouchAreaGrid(ent);
2304 if(clip & 8) // teleport
2307 if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2310 if (sv_nostep.integer)
2313 VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2314 VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2315 //originalmove_clip = clip;
2316 originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2317 originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2319 // if move didn't block on a step, return
2322 // if move was not trying to move into the step, return
2323 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2326 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
2328 // return if gibbed by a trigger
2329 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
2332 // only step up while jumping if that is enabled
2333 if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
2334 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2338 // try moving up and forward to go up a step
2339 // back to start pos
2340 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2341 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2344 VectorClear (upmove);
2345 upmove[2] = sv_stepheight.value;
2346 if(!SV_PushEntity(&trace, ent, upmove, false, true))
2348 // we got teleported when upstepping... must abort the move
2353 PRVM_serveredictvector(ent, velocity)[2] = 0;
2354 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
2355 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2358 // we got teleported when upstepping... must abort the move
2359 // note that z velocity handling may not be what QC expects here, but we cannot help it
2363 SV_CheckVelocity(ent);
2365 SV_LinkEdict_TouchAreaGrid(ent);
2367 // check for stuckness, possibly due to the limited precision of floats
2368 // in the clipping hulls
2370 && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2371 && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2373 //Con_Printf("wall\n");
2374 // stepping up didn't make any progress, revert to original move
2375 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2376 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2377 //clip = originalmove_clip;
2378 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2379 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2380 // now try to unstick if needed
2381 //clip = SV_TryUnstick (ent, oldvel);
2385 //Con_Printf("step - ");
2387 // extra friction based on view angle
2388 if (clip & 2 && sv_wallfriction.integer)
2389 SV_WallFriction (ent, stepnormal);
2391 // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2392 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))
2396 VectorClear (downmove);
2397 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2398 if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
2400 // we got teleported when downstepping... must abort the move
2404 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2406 // this has been disabled so that you can't jump when you are stepping
2407 // up while already jumping (also known as the Quake2 double jump bug)
2409 // LordHavoc: disabled this check so you can walk on monsters/players
2410 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2412 //Con_Printf("onground\n");
2413 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2414 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
2420 //Con_Printf("slope\n");
2421 // if the push down didn't end up on good ground, use the move without
2422 // the step up. This happens near wall / slope combinations, and can
2423 // cause the player to hop up higher on a slope too steep to climb
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;
2431 SV_CheckVelocity(ent);
2433 SV_LinkEdict_TouchAreaGrid(ent);
2436 //============================================================================
2442 Entities that are "stuck" to another entity
2445 void SV_Physics_Follow (prvm_edict_t *ent)
2447 vec3_t vf, vr, vu, angles, v;
2451 if (!SV_RunThink (ent))
2454 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2455 e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
2456 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])
2458 // quick case for no rotation
2459 VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
2463 angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
2464 angles[1] = PRVM_serveredictvector(ent, punchangle)[1];
2465 angles[2] = PRVM_serveredictvector(ent, punchangle)[2];
2466 AngleVectors (angles, vf, vr, vu);
2467 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];
2468 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];
2469 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];
2470 angles[0] = -PRVM_serveredictvector(e, angles)[0];
2471 angles[1] = PRVM_serveredictvector(e, angles)[1];
2472 angles[2] = PRVM_serveredictvector(e, angles)[2];
2473 AngleVectors (angles, vf, vr, vu);
2474 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2475 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2476 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2478 VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
2480 //SV_LinkEdict_TouchAreaGrid(ent);
2484 ==============================================================================
2488 ==============================================================================
2493 SV_CheckWaterTransition
2497 void SV_CheckWaterTransition (prvm_edict_t *ent)
2500 cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
2501 if (!PRVM_serveredictfloat(ent, watertype))
2503 // just spawned here
2504 PRVM_serveredictfloat(ent, watertype) = cont;
2505 PRVM_serveredictfloat(ent, waterlevel) = 1;
2509 // DRESK - Support for Entity Contents Transition Event
2510 // NOTE: Call here BEFORE updating the watertype below,
2511 // and suppress watersplash sound if a valid function
2512 // call was made to allow for custom "splash" sounds.
2513 if( !SV_CheckContentsTransition(ent, cont) )
2514 { // Contents Transition Function Invalid; Potentially Play Water Sound
2515 // check if the entity crossed into or out of water
2516 if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
2517 SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false);
2520 if (cont <= CONTENTS_WATER)
2522 PRVM_serveredictfloat(ent, watertype) = cont;
2523 PRVM_serveredictfloat(ent, waterlevel) = 1;
2527 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2528 PRVM_serveredictfloat(ent, waterlevel) = 0;
2536 Toss, bounce, and fly movement. When onground, do nothing.
2539 void SV_Physics_Toss (prvm_edict_t *ent)
2545 prvm_edict_t *groundentity;
2547 // if onground, return without moving
2548 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2550 groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
2551 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2553 // don't stick to ground if onground and moving upward
2554 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2556 else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
2558 // we can trust FL_ONGROUND if groundentity is world because it never moves
2561 else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
2563 // if ent was supported by a brush model on previous frame,
2564 // and groundentity is now freed, set groundentity to 0 (world)
2565 // which leaves it suspended in the air
2566 PRVM_serveredictedict(ent, groundentity) = 0;
2567 if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
2570 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2572 // don't slide if still touching the groundentity
2576 ent->priv.server->suspendedinairflag = false;
2578 SV_CheckVelocity (ent);
2581 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2582 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
2585 VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2587 movetime = sv.frametime;
2588 for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2591 VectorScale (PRVM_serveredictvector(ent, velocity), movetime, move);
2592 if(!SV_PushEntity (&trace, ent, move, true, true))
2593 return; // teleported
2594 if (ent->priv.server->free)
2596 if (trace.bmodelstartsolid)
2598 // try to unstick the entity
2599 SV_UnstickEntity(ent);
2600 if(!SV_PushEntity (&trace, ent, move, false, true))
2601 return; // teleported
2602 if (ent->priv.server->free)
2605 if (trace.fraction == 1)
2607 movetime *= 1 - min(1, trace.fraction);
2608 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
2611 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2613 bouncefactor = 1.0f;
2615 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2616 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2618 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2620 float d, ent_gravity;
2624 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2626 bouncefactor = 0.5f;
2628 bouncestop = PRVM_serveredictfloat(ent, bouncestop);
2630 bouncestop = 60.0f / 800.0f;
2632 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2633 ent_gravity = PRVM_serveredictfloat(ent, gravity);
2636 // LordHavoc: fixed grenades not bouncing when fired down a slope
2637 if (sv_gameplayfix_grenadebouncedownslopes.integer)
2639 d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
2640 if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
2642 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2643 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2644 VectorClear (PRVM_serveredictvector(ent, velocity));
2645 VectorClear (PRVM_serveredictvector(ent, avelocity));
2648 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2652 if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * bouncestop * ent_gravity)
2654 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2655 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2656 VectorClear (PRVM_serveredictvector(ent, velocity));
2657 VectorClear (PRVM_serveredictvector(ent, avelocity));
2660 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2665 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
2666 if (trace.plane.normal[2] > 0.7)
2668 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2669 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2670 if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
2671 ent->priv.server->suspendedinairflag = true;
2672 VectorClear (PRVM_serveredictvector(ent, velocity));
2673 VectorClear (PRVM_serveredictvector(ent, avelocity));
2676 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2678 if (!sv_gameplayfix_slidemoveprojectiles.integer || (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_BOUNCE && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE) || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2682 // check for in water
2683 SV_CheckWaterTransition (ent);
2687 ===============================================================================
2691 ===============================================================================
2698 Monsters freefall when they don't have a ground entity, otherwise
2699 all movement is done with discrete steps.
2701 This is also used for objects that have become still on the ground, but
2702 will fall if the floor is pulled out from under them.
2705 void SV_Physics_Step (prvm_edict_t *ent)
2707 int flags = (int)PRVM_serveredictfloat(ent, flags);
2710 // Backup Velocity in the event that movetypesteplandevent is called,
2711 // to provide a parameter with the entity's velocity at impact.
2712 vec3_t backupVelocity;
2713 VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2714 // don't fall at all if fly/swim
2715 if (!(flags & (FL_FLY | FL_SWIM)))
2717 if (flags & FL_ONGROUND)
2719 // freefall if onground and moving upward
2720 // freefall if not standing on a world surface (it may be a lift or trap door)
2721 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2723 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2724 SV_CheckVelocity(ent);
2725 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2727 SV_LinkEdict_TouchAreaGrid(ent);
2728 ent->priv.server->waterposition_forceupdate = true;
2733 // freefall if not onground
2734 int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2736 SV_CheckVelocity(ent);
2737 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2739 SV_LinkEdict_TouchAreaGrid(ent);
2742 if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2744 // DRESK - Check for Entity Land Event Function
2745 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2746 { // Valid Function; Execute
2747 // Prepare Parameters
2748 // Assign Velocity at Impact
2749 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2750 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2751 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2753 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2754 // Execute VM Function
2755 PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2758 // Check for Engine Landing Sound
2759 if(sv_sound_land.string)
2760 SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false);
2762 ent->priv.server->waterposition_forceupdate = true;
2767 if (!SV_RunThink(ent))
2770 if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2772 ent->priv.server->waterposition_forceupdate = false;
2773 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2774 SV_CheckWaterTransition(ent);
2778 //============================================================================
2780 static void SV_Physics_Entity (prvm_edict_t *ent)
2782 // don't run think/move on newly spawned projectiles as it messes up
2783 // movement interpolation and rocket trails, and is inconsistent with
2784 // respect to entities spawned in the same frame
2785 // (if an ent spawns a higher numbered ent, it moves in the same frame,
2786 // but if it spawns a lower numbered ent, it doesn't - this never moves
2787 // ents in the first frame regardless)
2788 qboolean runmove = ent->priv.server->move;
2789 ent->priv.server->move = true;
2790 if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2792 switch ((int) PRVM_serveredictfloat(ent, movetype))
2795 case MOVETYPE_FAKEPUSH:
2796 SV_Physics_Pusher (ent);
2799 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2800 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2803 case MOVETYPE_FOLLOW:
2804 SV_Physics_Follow (ent);
2806 case MOVETYPE_NOCLIP:
2807 if (SV_RunThink(ent))
2810 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2811 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2816 SV_Physics_Step (ent);
2819 if (SV_RunThink (ent))
2823 case MOVETYPE_BOUNCE:
2824 case MOVETYPE_BOUNCEMISSILE:
2825 case MOVETYPE_FLYMISSILE:
2828 if (SV_RunThink (ent))
2829 SV_Physics_Toss (ent);
2831 case MOVETYPE_PHYSICS:
2832 if (SV_RunThink(ent))
2835 SV_LinkEdict_TouchAreaGrid(ent);
2839 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2844 void SV_Physics_ClientMove(void)
2847 ent = host_client->edict;
2849 // call player physics, this needs the proper frametime
2850 PRVM_serverglobalfloat(frametime) = sv.frametime;
2853 // call standard client pre-think, with frametime = 0
2854 PRVM_serverglobalfloat(time) = sv.time;
2855 PRVM_serverglobalfloat(frametime) = 0;
2856 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2857 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2858 PRVM_serverglobalfloat(frametime) = sv.frametime;
2860 // make sure the velocity is sane (not a NaN)
2861 SV_CheckVelocity(ent);
2863 // perform MOVETYPE_WALK behavior
2866 // call standard player post-think, with frametime = 0
2867 PRVM_serverglobalfloat(time) = sv.time;
2868 PRVM_serverglobalfloat(frametime) = 0;
2869 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2870 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2871 PRVM_serverglobalfloat(frametime) = sv.frametime;
2873 if(PRVM_serveredictfloat(ent, fixangle))
2875 // angle fixing was requested by physics code...
2876 // so store the current angles for later use
2877 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2878 host_client->fixangle_angles_set = TRUE;
2880 // and clear fixangle for the next frame
2881 PRVM_serveredictfloat(ent, fixangle) = 0;
2885 static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
2887 // don't do physics on disconnected clients, FrikBot relies on this
2888 if (!host_client->spawned)
2891 // make sure the velocity is sane (not a NaN)
2892 SV_CheckVelocity(ent);
2894 // don't run physics here if running asynchronously
2895 if (host_client->clmovement_inputtimeout <= 0)
2898 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
2901 // make sure the velocity is still sane (not a NaN)
2902 SV_CheckVelocity(ent);
2904 // call standard client pre-think
2905 PRVM_serverglobalfloat(time) = sv.time;
2906 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2907 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2909 // make sure the velocity is still sane (not a NaN)
2910 SV_CheckVelocity(ent);
2913 static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
2915 // don't do physics on disconnected clients, FrikBot relies on this
2916 if (!host_client->spawned)
2919 // make sure the velocity is sane (not a NaN)
2920 SV_CheckVelocity(ent);
2922 // call standard player post-think
2923 PRVM_serverglobalfloat(time) = sv.time;
2924 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2925 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2927 // make sure the velocity is still sane (not a NaN)
2928 SV_CheckVelocity(ent);
2930 if(PRVM_serveredictfloat(ent, fixangle))
2932 // angle fixing was requested by physics code...
2933 // so store the current angles for later use
2934 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2935 host_client->fixangle_angles_set = TRUE;
2937 // and clear fixangle for the next frame
2938 PRVM_serveredictfloat(ent, fixangle) = 0;
2941 // decrement the countdown variable used to decide when to go back to
2942 // synchronous physics
2943 if (host_client->clmovement_inputtimeout > sv.frametime)
2944 host_client->clmovement_inputtimeout -= sv.frametime;
2946 host_client->clmovement_inputtimeout = 0;
2949 static void SV_Physics_ClientEntity(prvm_edict_t *ent)
2951 // don't do physics on disconnected clients, FrikBot relies on this
2952 if (!host_client->spawned)
2954 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
2958 // make sure the velocity is sane (not a NaN)
2959 SV_CheckVelocity(ent);
2961 switch ((int) PRVM_serveredictfloat(ent, movetype))
2964 case MOVETYPE_FAKEPUSH:
2965 SV_Physics_Pusher (ent);
2968 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2969 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2972 case MOVETYPE_FOLLOW:
2973 SV_Physics_Follow (ent);
2975 case MOVETYPE_NOCLIP:
2978 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2979 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2982 SV_Physics_Step (ent);
2986 // don't run physics here if running asynchronously
2987 if (host_client->clmovement_inputtimeout <= 0)
2991 case MOVETYPE_BOUNCE:
2992 case MOVETYPE_BOUNCEMISSILE:
2993 case MOVETYPE_FLYMISSILE:
2996 SV_Physics_Toss (ent);
3002 case MOVETYPE_PHYSICS:
3006 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
3010 SV_CheckVelocity (ent);
3013 SV_LinkEdict_TouchAreaGrid(ent);
3015 SV_CheckVelocity (ent);
3024 void SV_Physics (void)
3029 // let the progs know that a new frame has started
3030 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3031 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3032 PRVM_serverglobalfloat(time) = sv.time;
3033 PRVM_serverglobalfloat(frametime) = sv.frametime;
3034 PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
3036 // run physics engine
3037 World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
3040 // treat each object in turn
3043 // if force_retouch, relink all the entities
3044 if (PRVM_serverglobalfloat(force_retouch) > 0)
3045 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3046 if (!ent->priv.server->free)
3047 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
3049 if (sv_gameplayfix_consistentplayerprethink.integer)
3051 // run physics on the client entities in 3 stages
3052 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3053 if (!ent->priv.server->free)
3054 SV_Physics_ClientEntity_PreThink(ent);
3056 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3057 if (!ent->priv.server->free)
3058 SV_Physics_ClientEntity(ent);
3060 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3061 if (!ent->priv.server->free)
3062 SV_Physics_ClientEntity_PostThink(ent);
3066 // run physics on the client entities
3067 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3069 if (!ent->priv.server->free)
3071 SV_Physics_ClientEntity_PreThink(ent);
3072 SV_Physics_ClientEntity(ent);
3073 SV_Physics_ClientEntity_PostThink(ent);
3078 // run physics on all the non-client entities
3079 if (!sv_freezenonclients.integer)
3081 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3082 if (!ent->priv.server->free)
3083 SV_Physics_Entity(ent);
3084 // make a second pass to see if any ents spawned this frame and make
3085 // sure they run their move/think
3086 if (sv_gameplayfix_delayprojectiles.integer < 0)
3087 for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3088 if (!ent->priv.server->move && !ent->priv.server->free)
3089 SV_Physics_Entity(ent);
3092 if (PRVM_serverglobalfloat(force_retouch) > 0)
3093 PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
3095 // LordHavoc: endframe support
3096 if (PRVM_serverfunction(EndFrame))
3098 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3099 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3100 PRVM_serverglobalfloat(time) = sv.time;
3101 PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3104 // decrement prog->num_edicts if the highest number entities died
3105 for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3107 if (!sv_freezenonclients.integer)
3108 sv.time += sv.frametime;