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 if (PRVM_serveredictfloat(pusher, movetype) == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
1775 numcheckentities = 0;
1776 else // MOVETYPE_PUSH
1777 numcheckentities = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, checkentities);
1778 for (e = 0;e < numcheckentities;e++)
1780 prvm_edict_t *check = checkentities[e];
1781 int movetype = (int)PRVM_serveredictfloat(check, movetype);
1786 case MOVETYPE_FOLLOW:
1787 case MOVETYPE_NOCLIP:
1793 if (PRVM_serveredictedict(check, owner) == pusherprog)
1796 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1799 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1801 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1802 check->priv.server->waterposition_forceupdate = true;
1804 checkcontents = SV_GenericHitSuperContentsMask(check);
1806 // if the entity is standing on the pusher, it will definitely be moved
1807 // if the entity is not standing on the pusher, but is in the pusher's
1808 // final position, move it
1809 if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
1811 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);
1812 //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1813 if (!trace.startsolid)
1815 //Con_Printf("- not in solid\n");
1820 VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot);
1821 //VectorClear(pivot);
1826 VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org);
1827 VectorAdd (org, pivot, org);
1828 org2[0] = DotProduct (org, forward);
1829 org2[1] = DotProduct (org, left);
1830 org2[2] = DotProduct (org, up);
1831 VectorSubtract (org2, org, move);
1832 VectorAdd (move, move1, move);
1835 VectorCopy (move1, move);
1837 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1839 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1840 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1841 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1843 // physics objects need better collisions than this code can do
1844 if (movetype == MOVETYPE_PHYSICS)
1846 VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
1847 SV_LinkEdict(check);
1848 SV_LinkEdict_TouchAreaGrid(check);
1852 // try moving the contacted entity
1853 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1854 if(!SV_PushEntity (&trace, check, move, true, true))
1856 // entity "check" got teleported
1857 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1858 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1859 continue; // pushed enough
1861 // FIXME: turn players specially
1862 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1863 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1864 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1866 // this trace.fraction < 1 check causes items to fall off of pushers
1867 // if they pass under or through a wall
1868 // the groundentity check causes items to fall off of ledges
1869 if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
1870 PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1872 // if it is still inside the pusher, block
1873 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);
1874 if (trace.startsolid)
1877 if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
1879 // hack to invoke all necessary movement triggers
1881 if(!SV_PushEntity(&trace2, check, move2, true, true))
1883 // entity "check" got teleported
1890 // still inside pusher, so it's really blocked
1893 if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1895 if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER)
1898 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1899 VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs));
1903 VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1904 VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1905 PRVM_serveredictfloat(pusher, ltime) = pushltime;
1906 SV_LinkEdict(pusher);
1908 // move back any entities we already moved
1909 for (i = 0;i < num_moved;i++)
1911 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1912 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1913 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
1917 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
1918 if (PRVM_serveredictfunction(pusher, blocked))
1920 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
1921 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
1922 PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
1927 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1928 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1929 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1938 void SV_Physics_Pusher (prvm_edict_t *ent)
1940 float thinktime, oldltime, movetime;
1942 oldltime = PRVM_serveredictfloat(ent, ltime);
1944 thinktime = PRVM_serveredictfloat(ent, nextthink);
1945 if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
1947 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
1952 movetime = sv.frametime;
1955 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
1956 SV_PushMove (ent, movetime);
1958 if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
1960 PRVM_serveredictfloat(ent, nextthink) = 0;
1961 PRVM_serverglobalfloat(time) = sv.time;
1962 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1963 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1964 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1970 ===============================================================================
1974 ===============================================================================
1977 static float unstickoffsets[] =
1979 // poutting -/+z changes first as they are least weird
1994 typedef enum unstickresult_e
2002 unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
2006 // if not stuck in a bmodel, just return
2007 if (!SV_TestEntityPosition(ent, vec3_origin))
2008 return UNSTICK_GOOD;
2010 for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
2012 if (!SV_TestEntityPosition(ent, unstickoffsets + i))
2014 VectorCopy(unstickoffsets + i, offset);
2016 //SV_LinkEdict_TouchAreaGrid(ent);
2017 return UNSTICK_UNSTUCK;
2021 maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
2022 // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
2024 for(i = 2; i <= maxunstick; ++i)
2026 VectorClear(offset);
2028 if (!SV_TestEntityPosition(ent, offset))
2031 //SV_LinkEdict_TouchAreaGrid(ent);
2032 return UNSTICK_UNSTUCK;
2035 if (!SV_TestEntityPosition(ent, offset))
2038 //SV_LinkEdict_TouchAreaGrid(ent);
2039 return UNSTICK_UNSTUCK;
2043 return UNSTICK_STUCK;
2046 qboolean SV_UnstickEntity (prvm_edict_t *ent)
2049 switch(SV_UnstickEntityReturnOffset(ent, offset))
2053 case UNSTICK_UNSTUCK:
2054 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]);
2057 if (developer_extra.integer)
2058 Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2061 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2070 This is a big hack to try and fix the rare case of getting stuck in the world
2074 void SV_CheckStuck (prvm_edict_t *ent)
2078 switch(SV_UnstickEntityReturnOffset(ent, offset))
2081 VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
2083 case UNSTICK_UNSTUCK:
2084 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]);
2087 VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
2088 if (!SV_TestEntityPosition(ent, offset))
2090 Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2092 //SV_LinkEdict_TouchAreaGrid(ent);
2095 Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2098 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2108 qboolean SV_CheckWater (prvm_edict_t *ent)
2111 int nNativeContents;
2114 point[0] = PRVM_serveredictvector(ent, origin)[0];
2115 point[1] = PRVM_serveredictvector(ent, origin)[1];
2116 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2118 // DRESK - Support for Entity Contents Transition Event
2119 // NOTE: Some logic needed to be slightly re-ordered
2120 // to not affect performance and allow for the feature.
2122 // Acquire Super Contents Prior to Resets
2123 cont = SV_PointSuperContents(point);
2124 // Acquire Native Contents Here
2125 nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
2127 // DRESK - Support for Entity Contents Transition Event
2128 if(PRVM_serveredictfloat(ent, watertype))
2129 // Entity did NOT Spawn; Check
2130 SV_CheckContentsTransition(ent, nNativeContents);
2133 PRVM_serveredictfloat(ent, waterlevel) = 0;
2134 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2135 cont = SV_PointSuperContents(point);
2136 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2138 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2139 PRVM_serveredictfloat(ent, waterlevel) = 1;
2140 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2141 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2143 PRVM_serveredictfloat(ent, waterlevel) = 2;
2144 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2145 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2146 PRVM_serveredictfloat(ent, waterlevel) = 3;
2150 return PRVM_serveredictfloat(ent, waterlevel) > 1;
2159 void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2162 vec3_t forward, into, side;
2164 AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
2165 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2167 // cut the tangential velocity
2168 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2169 VectorScale (stepnormal, i, into);
2170 VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
2171 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2172 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2178 =====================
2181 Player has come to a dead stop, possibly due to the problem with limited
2182 float precision at some angle joins in the BSP hull.
2184 Try fixing by pushing one pixel in each direction.
2186 This is a hack, but in the interest of good gameplay...
2187 ======================
2189 int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2194 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
2197 for (i=0 ; i<8 ; i++)
2199 // try pushing a little in an axial direction
2202 case 0: dir[0] = 2; dir[1] = 0; break;
2203 case 1: dir[0] = 0; dir[1] = 2; break;
2204 case 2: dir[0] = -2; dir[1] = 0; break;
2205 case 3: dir[0] = 0; dir[1] = -2; break;
2206 case 4: dir[0] = 2; dir[1] = 2; break;
2207 case 5: dir[0] = -2; dir[1] = 2; break;
2208 case 6: dir[0] = 2; dir[1] = -2; break;
2209 case 7: dir[0] = -2; dir[1] = -2; break;
2212 SV_PushEntity (&trace, ent, dir, false, true);
2214 // retry the original move
2215 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2216 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2217 PRVM_serveredictvector(ent, velocity)[2] = 0;
2218 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
2220 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2221 || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2223 Con_DPrint("TryUnstick - success.\n");
2227 // go back to the original pos and try again
2228 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
2232 VectorClear (PRVM_serveredictvector(ent, velocity));
2233 Con_DPrint("TryUnstick - failure.\n");
2239 =====================
2242 Only used by players
2243 ======================
2245 void SV_WalkMove (prvm_edict_t *ent)
2249 //int originalmove_clip;
2250 int originalmove_flags;
2251 int originalmove_groundentity;
2252 int hitsupercontentsmask;
2254 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
2255 trace_t downtrace, trace;
2256 qboolean applygravity;
2258 // if frametime is 0 (due to client sending the same timestamp twice),
2260 if (sv.frametime <= 0)
2263 SV_CheckStuck (ent);
2265 applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2267 hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2269 SV_CheckVelocity(ent);
2271 // do a regular slide move unless it looks like you ran into a step
2272 oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2274 VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2275 VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2277 clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2279 if(sv_gameplayfix_downtracesupportsongroundflag.integer)
2282 // only try this if there was no floor in the way in the trace (no,
2283 // this check seems to be not REALLY necessary, because if clip & 1,
2284 // our trace will hit that thing too)
2285 VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
2286 VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
2287 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
2288 type = MOVE_MISSILE;
2289 else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
2290 type = MOVE_NOMONSTERS; // only clip against bmodels
2293 trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
2294 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2295 clip |= 1; // but we HAVE found a floor
2298 // if the move did not hit the ground at any point, we're not on ground
2300 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2302 SV_CheckVelocity(ent);
2304 SV_LinkEdict_TouchAreaGrid(ent);
2306 if(clip & 8) // teleport
2309 if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2312 if (sv_nostep.integer)
2315 VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2316 VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2317 //originalmove_clip = clip;
2318 originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2319 originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2321 // if move didn't block on a step, return
2324 // if move was not trying to move into the step, return
2325 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2328 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
2330 // return if gibbed by a trigger
2331 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
2334 // only step up while jumping if that is enabled
2335 if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
2336 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2340 // try moving up and forward to go up a step
2341 // back to start pos
2342 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2343 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2346 VectorClear (upmove);
2347 upmove[2] = sv_stepheight.value;
2348 if(!SV_PushEntity(&trace, ent, upmove, false, true))
2350 // we got teleported when upstepping... must abort the move
2355 PRVM_serveredictvector(ent, velocity)[2] = 0;
2356 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
2357 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2360 // we got teleported when upstepping... must abort the move
2361 // note that z velocity handling may not be what QC expects here, but we cannot help it
2365 SV_CheckVelocity(ent);
2367 SV_LinkEdict_TouchAreaGrid(ent);
2369 // check for stuckness, possibly due to the limited precision of floats
2370 // in the clipping hulls
2372 && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2373 && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2375 //Con_Printf("wall\n");
2376 // stepping up didn't make any progress, revert to original move
2377 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2378 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2379 //clip = originalmove_clip;
2380 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2381 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2382 // now try to unstick if needed
2383 //clip = SV_TryUnstick (ent, oldvel);
2387 //Con_Printf("step - ");
2389 // extra friction based on view angle
2390 if (clip & 2 && sv_wallfriction.integer)
2391 SV_WallFriction (ent, stepnormal);
2393 // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2394 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))
2398 VectorClear (downmove);
2399 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2400 if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
2402 // we got teleported when downstepping... must abort the move
2406 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2408 // this has been disabled so that you can't jump when you are stepping
2409 // up while already jumping (also known as the Quake2 double jump bug)
2411 // LordHavoc: disabled this check so you can walk on monsters/players
2412 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2414 //Con_Printf("onground\n");
2415 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2416 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
2422 //Con_Printf("slope\n");
2423 // if the push down didn't end up on good ground, use the move without
2424 // the step up. This happens near wall / slope combinations, and can
2425 // cause the player to hop up higher on a slope too steep to climb
2426 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2427 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2428 //clip = originalmove_clip;
2429 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2430 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2433 SV_CheckVelocity(ent);
2435 SV_LinkEdict_TouchAreaGrid(ent);
2438 //============================================================================
2444 Entities that are "stuck" to another entity
2447 void SV_Physics_Follow (prvm_edict_t *ent)
2449 vec3_t vf, vr, vu, angles, v;
2453 if (!SV_RunThink (ent))
2456 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2457 e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
2458 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])
2460 // quick case for no rotation
2461 VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
2465 angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
2466 angles[1] = PRVM_serveredictvector(ent, punchangle)[1];
2467 angles[2] = PRVM_serveredictvector(ent, punchangle)[2];
2468 AngleVectors (angles, vf, vr, vu);
2469 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];
2470 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];
2471 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];
2472 angles[0] = -PRVM_serveredictvector(e, angles)[0];
2473 angles[1] = PRVM_serveredictvector(e, angles)[1];
2474 angles[2] = PRVM_serveredictvector(e, angles)[2];
2475 AngleVectors (angles, vf, vr, vu);
2476 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2477 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2478 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2480 VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
2482 //SV_LinkEdict_TouchAreaGrid(ent);
2486 ==============================================================================
2490 ==============================================================================
2495 SV_CheckWaterTransition
2499 void SV_CheckWaterTransition (prvm_edict_t *ent)
2502 cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
2503 if (!PRVM_serveredictfloat(ent, watertype))
2505 // just spawned here
2506 PRVM_serveredictfloat(ent, watertype) = cont;
2507 PRVM_serveredictfloat(ent, waterlevel) = 1;
2511 // DRESK - Support for Entity Contents Transition Event
2512 // NOTE: Call here BEFORE updating the watertype below,
2513 // and suppress watersplash sound if a valid function
2514 // call was made to allow for custom "splash" sounds.
2515 if( !SV_CheckContentsTransition(ent, cont) )
2516 { // Contents Transition Function Invalid; Potentially Play Water Sound
2517 // check if the entity crossed into or out of water
2518 if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
2519 SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false);
2522 if (cont <= CONTENTS_WATER)
2524 PRVM_serveredictfloat(ent, watertype) = cont;
2525 PRVM_serveredictfloat(ent, waterlevel) = 1;
2529 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2530 PRVM_serveredictfloat(ent, waterlevel) = 0;
2538 Toss, bounce, and fly movement. When onground, do nothing.
2541 void SV_Physics_Toss (prvm_edict_t *ent)
2547 prvm_edict_t *groundentity;
2549 // if onground, return without moving
2550 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2552 groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
2553 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2555 // don't stick to ground if onground and moving upward
2556 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2558 else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
2560 // we can trust FL_ONGROUND if groundentity is world because it never moves
2563 else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
2565 // if ent was supported by a brush model on previous frame,
2566 // and groundentity is now freed, set groundentity to 0 (world)
2567 // which leaves it suspended in the air
2568 PRVM_serveredictedict(ent, groundentity) = 0;
2569 if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
2572 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2574 // don't slide if still touching the groundentity
2578 ent->priv.server->suspendedinairflag = false;
2580 SV_CheckVelocity (ent);
2583 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2584 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
2587 VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2589 movetime = sv.frametime;
2590 for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2593 VectorScale (PRVM_serveredictvector(ent, velocity), movetime, move);
2594 if(!SV_PushEntity (&trace, ent, move, true, true))
2595 return; // teleported
2596 if (ent->priv.server->free)
2598 if (trace.bmodelstartsolid)
2600 // try to unstick the entity
2601 SV_UnstickEntity(ent);
2602 if(!SV_PushEntity (&trace, ent, move, false, true))
2603 return; // teleported
2604 if (ent->priv.server->free)
2607 if (trace.fraction == 1)
2609 movetime *= 1 - min(1, trace.fraction);
2610 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
2613 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2615 bouncefactor = 1.0f;
2617 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2618 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2620 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2622 float d, ent_gravity;
2626 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2628 bouncefactor = 0.5f;
2630 bouncestop = PRVM_serveredictfloat(ent, bouncestop);
2632 bouncestop = 60.0f / 800.0f;
2634 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2635 ent_gravity = PRVM_serveredictfloat(ent, gravity);
2638 // LordHavoc: fixed grenades not bouncing when fired down a slope
2639 if (sv_gameplayfix_grenadebouncedownslopes.integer)
2641 d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
2642 if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
2644 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2645 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2646 VectorClear (PRVM_serveredictvector(ent, velocity));
2647 VectorClear (PRVM_serveredictvector(ent, avelocity));
2650 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2654 if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * bouncestop * ent_gravity)
2656 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2657 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2658 VectorClear (PRVM_serveredictvector(ent, velocity));
2659 VectorClear (PRVM_serveredictvector(ent, avelocity));
2662 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2667 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
2668 if (trace.plane.normal[2] > 0.7)
2670 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2671 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2672 if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
2673 ent->priv.server->suspendedinairflag = true;
2674 VectorClear (PRVM_serveredictvector(ent, velocity));
2675 VectorClear (PRVM_serveredictvector(ent, avelocity));
2678 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2680 if (!sv_gameplayfix_slidemoveprojectiles.integer || (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_BOUNCE && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE) || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2684 // check for in water
2685 SV_CheckWaterTransition (ent);
2689 ===============================================================================
2693 ===============================================================================
2700 Monsters freefall when they don't have a ground entity, otherwise
2701 all movement is done with discrete steps.
2703 This is also used for objects that have become still on the ground, but
2704 will fall if the floor is pulled out from under them.
2707 void SV_Physics_Step (prvm_edict_t *ent)
2709 int flags = (int)PRVM_serveredictfloat(ent, flags);
2712 // Backup Velocity in the event that movetypesteplandevent is called,
2713 // to provide a parameter with the entity's velocity at impact.
2714 vec3_t backupVelocity;
2715 VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2716 // don't fall at all if fly/swim
2717 if (!(flags & (FL_FLY | FL_SWIM)))
2719 if (flags & FL_ONGROUND)
2721 // freefall if onground and moving upward
2722 // freefall if not standing on a world surface (it may be a lift or trap door)
2723 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2725 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2726 SV_CheckVelocity(ent);
2727 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2729 SV_LinkEdict_TouchAreaGrid(ent);
2730 ent->priv.server->waterposition_forceupdate = true;
2735 // freefall if not onground
2736 int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2738 SV_CheckVelocity(ent);
2739 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2741 SV_LinkEdict_TouchAreaGrid(ent);
2744 if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2746 // DRESK - Check for Entity Land Event Function
2747 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2748 { // Valid Function; Execute
2749 // Prepare Parameters
2750 // Assign Velocity at Impact
2751 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2752 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2753 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2755 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2756 // Execute VM Function
2757 PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2760 // Check for Engine Landing Sound
2761 if(sv_sound_land.string)
2762 SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false);
2764 ent->priv.server->waterposition_forceupdate = true;
2769 if (!SV_RunThink(ent))
2772 if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2774 ent->priv.server->waterposition_forceupdate = false;
2775 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2776 SV_CheckWaterTransition(ent);
2780 //============================================================================
2782 static void SV_Physics_Entity (prvm_edict_t *ent)
2784 // don't run think/move on newly spawned projectiles as it messes up
2785 // movement interpolation and rocket trails, and is inconsistent with
2786 // respect to entities spawned in the same frame
2787 // (if an ent spawns a higher numbered ent, it moves in the same frame,
2788 // but if it spawns a lower numbered ent, it doesn't - this never moves
2789 // ents in the first frame regardless)
2790 qboolean runmove = ent->priv.server->move;
2791 ent->priv.server->move = true;
2792 if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2794 switch ((int) PRVM_serveredictfloat(ent, movetype))
2797 case MOVETYPE_FAKEPUSH:
2798 SV_Physics_Pusher (ent);
2801 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2802 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2805 case MOVETYPE_FOLLOW:
2806 SV_Physics_Follow (ent);
2808 case MOVETYPE_NOCLIP:
2809 if (SV_RunThink(ent))
2812 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2813 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2818 SV_Physics_Step (ent);
2821 if (SV_RunThink (ent))
2825 case MOVETYPE_BOUNCE:
2826 case MOVETYPE_BOUNCEMISSILE:
2827 case MOVETYPE_FLYMISSILE:
2830 if (SV_RunThink (ent))
2831 SV_Physics_Toss (ent);
2833 case MOVETYPE_PHYSICS:
2834 if (SV_RunThink(ent))
2837 SV_LinkEdict_TouchAreaGrid(ent);
2841 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2846 void SV_Physics_ClientMove(void)
2849 ent = host_client->edict;
2851 // call player physics, this needs the proper frametime
2852 PRVM_serverglobalfloat(frametime) = sv.frametime;
2855 // call standard client pre-think, with frametime = 0
2856 PRVM_serverglobalfloat(time) = sv.time;
2857 PRVM_serverglobalfloat(frametime) = 0;
2858 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2859 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2860 PRVM_serverglobalfloat(frametime) = sv.frametime;
2862 // make sure the velocity is sane (not a NaN)
2863 SV_CheckVelocity(ent);
2865 // perform MOVETYPE_WALK behavior
2868 // call standard player post-think, with frametime = 0
2869 PRVM_serverglobalfloat(time) = sv.time;
2870 PRVM_serverglobalfloat(frametime) = 0;
2871 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2872 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2873 PRVM_serverglobalfloat(frametime) = sv.frametime;
2875 if(PRVM_serveredictfloat(ent, fixangle))
2877 // angle fixing was requested by physics code...
2878 // so store the current angles for later use
2879 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2880 host_client->fixangle_angles_set = TRUE;
2882 // and clear fixangle for the next frame
2883 PRVM_serveredictfloat(ent, fixangle) = 0;
2887 static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
2889 // don't do physics on disconnected clients, FrikBot relies on this
2890 if (!host_client->spawned)
2893 // make sure the velocity is sane (not a NaN)
2894 SV_CheckVelocity(ent);
2896 // don't run physics here if running asynchronously
2897 if (host_client->clmovement_inputtimeout <= 0)
2900 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
2903 // make sure the velocity is still sane (not a NaN)
2904 SV_CheckVelocity(ent);
2906 // call standard client pre-think
2907 PRVM_serverglobalfloat(time) = sv.time;
2908 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2909 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2911 // make sure the velocity is still sane (not a NaN)
2912 SV_CheckVelocity(ent);
2915 static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
2917 // don't do physics on disconnected clients, FrikBot relies on this
2918 if (!host_client->spawned)
2921 // make sure the velocity is sane (not a NaN)
2922 SV_CheckVelocity(ent);
2924 // call standard player post-think
2925 PRVM_serverglobalfloat(time) = sv.time;
2926 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2927 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2929 // make sure the velocity is still sane (not a NaN)
2930 SV_CheckVelocity(ent);
2932 if(PRVM_serveredictfloat(ent, fixangle))
2934 // angle fixing was requested by physics code...
2935 // so store the current angles for later use
2936 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2937 host_client->fixangle_angles_set = TRUE;
2939 // and clear fixangle for the next frame
2940 PRVM_serveredictfloat(ent, fixangle) = 0;
2943 // decrement the countdown variable used to decide when to go back to
2944 // synchronous physics
2945 if (host_client->clmovement_inputtimeout > sv.frametime)
2946 host_client->clmovement_inputtimeout -= sv.frametime;
2948 host_client->clmovement_inputtimeout = 0;
2951 static void SV_Physics_ClientEntity(prvm_edict_t *ent)
2953 // don't do physics on disconnected clients, FrikBot relies on this
2954 if (!host_client->spawned)
2956 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
2960 // make sure the velocity is sane (not a NaN)
2961 SV_CheckVelocity(ent);
2963 switch ((int) PRVM_serveredictfloat(ent, movetype))
2966 case MOVETYPE_FAKEPUSH:
2967 SV_Physics_Pusher (ent);
2970 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2971 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2974 case MOVETYPE_FOLLOW:
2975 SV_Physics_Follow (ent);
2977 case MOVETYPE_NOCLIP:
2980 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2981 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2984 SV_Physics_Step (ent);
2988 // don't run physics here if running asynchronously
2989 if (host_client->clmovement_inputtimeout <= 0)
2993 case MOVETYPE_BOUNCE:
2994 case MOVETYPE_BOUNCEMISSILE:
2995 case MOVETYPE_FLYMISSILE:
2998 SV_Physics_Toss (ent);
3004 case MOVETYPE_PHYSICS:
3008 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
3012 SV_CheckVelocity (ent);
3015 SV_LinkEdict_TouchAreaGrid(ent);
3017 SV_CheckVelocity (ent);
3026 void SV_Physics (void)
3031 // let the progs know that a new frame has started
3032 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3033 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3034 PRVM_serverglobalfloat(time) = sv.time;
3035 PRVM_serverglobalfloat(frametime) = sv.frametime;
3036 PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
3038 // run physics engine
3039 World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
3042 // treat each object in turn
3045 // if force_retouch, relink all the entities
3046 if (PRVM_serverglobalfloat(force_retouch) > 0)
3047 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3048 if (!ent->priv.server->free)
3049 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
3051 if (sv_gameplayfix_consistentplayerprethink.integer)
3053 // run physics on the client entities in 3 stages
3054 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3055 if (!ent->priv.server->free)
3056 SV_Physics_ClientEntity_PreThink(ent);
3058 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3059 if (!ent->priv.server->free)
3060 SV_Physics_ClientEntity(ent);
3062 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3063 if (!ent->priv.server->free)
3064 SV_Physics_ClientEntity_PostThink(ent);
3068 // run physics on the client entities
3069 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3071 if (!ent->priv.server->free)
3073 SV_Physics_ClientEntity_PreThink(ent);
3074 SV_Physics_ClientEntity(ent);
3075 SV_Physics_ClientEntity_PostThink(ent);
3080 // run physics on all the non-client entities
3081 if (!sv_freezenonclients.integer)
3083 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3084 if (!ent->priv.server->free)
3085 SV_Physics_Entity(ent);
3086 // make a second pass to see if any ents spawned this frame and make
3087 // sure they run their move/think
3088 if (sv_gameplayfix_delayprojectiles.integer < 0)
3089 for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3090 if (!ent->priv.server->move && !ent->priv.server->free)
3091 SV_Physics_Entity(ent);
3094 if (PRVM_serverglobalfloat(force_retouch) > 0)
3095 PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
3097 // LordHavoc: endframe support
3098 if (PRVM_serverfunction(EndFrame))
3100 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3101 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3102 PRVM_serverglobalfloat(time) = sv.time;
3103 PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3106 // decrement prog->num_edicts if the highest number entities died
3107 for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3109 if (!sv_freezenonclients.integer)
3110 sv.time += sv.frametime;