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 ===============================================================================
1456 Does not change the entities velocity at all
1457 The trace struct is filled with the trace that has been done.
1458 Returns true if the push did not result in the entity being teleported by QC code.
1461 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
1468 vec3_t original, original_velocity;
1472 solid = (int)PRVM_serveredictfloat(ent, solid);
1473 movetype = (int)PRVM_serveredictfloat(ent, movetype);
1474 VectorCopy(PRVM_serveredictvector(ent, mins), mins);
1475 VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
1477 // move start position out of solids
1478 if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
1482 vec3_t stuckmins, stuckmaxs;
1484 vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
1485 if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
1486 separation = 0.0f; // when using hulls, it can not be enlarged
1487 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1488 VectorCopy(mins, stuckmins);
1489 VectorCopy(maxs, stuckmaxs);
1490 stuckmins[0] -= separation;
1491 stuckmins[1] -= separation;
1492 stuckmins[2] -= separation;
1493 stuckmaxs[0] += separation;
1494 stuckmaxs[1] += separation;
1495 stuckmaxs[2] += separation;
1496 for (bump = 0;bump < 10;bump++)
1498 stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1499 if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
1501 // found a good location, use it
1502 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1505 nudge = -stucktrace.startdepth;
1506 VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
1510 VectorCopy(PRVM_serveredictvector(ent, origin), start);
1511 VectorAdd(start, push, end);
1513 if (movetype == MOVETYPE_FLYMISSILE)
1514 type = MOVE_MISSILE;
1515 else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
1516 type = MOVE_NOMONSTERS; // only clip against bmodels
1520 *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
1521 if (trace->bmodelstartsolid && failonbmodelstartsolid)
1524 VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
1526 VectorCopy(PRVM_serveredictvector(ent, origin), original);
1527 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1532 if(!trace->startsolid)
1533 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)
1535 Con_Printf("something eeeeevil happened\n");
1540 SV_LinkEdict_TouchAreaGrid(ent);
1542 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))))
1543 SV_Impact (ent, trace);
1545 return VectorCompare(PRVM_serveredictvector(ent, origin), original) && VectorCompare(PRVM_serveredictvector(ent, velocity), original_velocity);
1555 void SV_PushMove (prvm_edict_t *pusher, float movetime)
1558 int pusherowner, pusherprog;
1561 float savesolid, movetime2, pushltime;
1562 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org;
1564 int numcheckentities;
1565 static prvm_edict_t *checkentities[MAX_EDICTS];
1566 dp_model_t *pushermodel;
1567 trace_t trace, trace2;
1568 matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
1569 static unsigned short moved_edicts[MAX_EDICTS];
1571 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])
1573 PRVM_serveredictfloat(pusher, ltime) += movetime;
1577 switch ((int) PRVM_serveredictfloat(pusher, solid))
1579 // LordHavoc: valid pusher types
1582 case SOLID_SLIDEBOX:
1583 case SOLID_CORPSE: // LordHavoc: this would be weird...
1585 // LordHavoc: no collisions
1588 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1589 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1590 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1591 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1592 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1593 PRVM_serveredictfloat(pusher, ltime) += movetime;
1594 SV_LinkEdict(pusher);
1597 Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
1600 index = (int) PRVM_serveredictfloat(pusher, modelindex);
1601 if (index < 1 || index >= MAX_MODELS)
1603 Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
1606 pushermodel = SV_GetModelByIndex(index);
1607 pusherowner = PRVM_serveredictedict(pusher, owner);
1608 pusherprog = PRVM_EDICT_TO_PROG(pusher);
1610 rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0;
1612 movetime2 = movetime;
1613 VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
1614 VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
1615 if (moveangle[0] || moveangle[2])
1617 for (i = 0;i < 3;i++)
1621 mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1622 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1626 mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1627 maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1631 else if (moveangle[1])
1633 for (i = 0;i < 3;i++)
1637 mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1638 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1642 mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1643 maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1649 for (i = 0;i < 3;i++)
1653 mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1654 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1658 mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1659 maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1664 VectorNegate (moveangle, a);
1665 AngleVectorsFLU (a, forward, left, up);
1667 VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
1668 VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
1669 pushltime = PRVM_serveredictfloat(pusher, ltime);
1671 // move the pusher to its final position
1673 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1674 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1675 PRVM_serveredictfloat(pusher, ltime) += movetime;
1676 SV_LinkEdict(pusher);
1678 pushermodel = SV_GetModelFromEdict(pusher);
1679 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);
1680 Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
1682 savesolid = PRVM_serveredictfloat(pusher, solid);
1684 // see if any solid entities are inside the final position
1687 numcheckentities = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, checkentities);
1688 for (e = 0;e < numcheckentities;e++)
1690 prvm_edict_t *check = checkentities[e];
1691 int movetype = (int)PRVM_serveredictfloat(check, movetype);
1696 case MOVETYPE_FOLLOW:
1697 case MOVETYPE_NOCLIP:
1698 case MOVETYPE_FAKEPUSH:
1704 if (PRVM_serveredictedict(check, owner) == pusherprog)
1707 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1710 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1712 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1713 check->priv.server->waterposition_forceupdate = true;
1715 checkcontents = SV_GenericHitSuperContentsMask(check);
1717 // if the entity is standing on the pusher, it will definitely be moved
1718 // if the entity is not standing on the pusher, but is in the pusher's
1719 // final position, move it
1720 if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
1722 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);
1723 //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1724 if (!trace.startsolid)
1726 //Con_Printf("- not in solid\n");
1734 VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org);
1735 org2[0] = DotProduct (org, forward);
1736 org2[1] = DotProduct (org, left);
1737 org2[2] = DotProduct (org, up);
1738 VectorSubtract (org2, org, move);
1739 VectorAdd (move, move1, move);
1742 VectorCopy (move1, move);
1744 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1746 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1747 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1748 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1750 // physics objects need better collisions than this code can do
1751 if (movetype == MOVETYPE_PHYSICS)
1753 VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
1754 SV_LinkEdict(check);
1755 SV_LinkEdict_TouchAreaGrid(check);
1759 // try moving the contacted entity
1760 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1761 if(!SV_PushEntity (&trace, check, move, true, true))
1763 // entity "check" got teleported
1764 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1765 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1766 continue; // pushed enough
1768 // FIXME: turn players specially
1769 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1770 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1771 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1773 // this trace.fraction < 1 check causes items to fall off of pushers
1774 // if they pass under or through a wall
1775 // the groundentity check causes items to fall off of ledges
1776 if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
1777 PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1779 // if it is still inside the pusher, block
1780 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);
1781 if (trace.startsolid)
1783 // try moving the contacted entity a tiny bit further to account for precision errors
1785 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1786 VectorScale(move, 1.1, move2);
1787 VectorCopy (check->priv.server->moved_from, PRVM_serveredictvector(check, origin));
1788 VectorCopy (check->priv.server->moved_fromangles, PRVM_serveredictvector(check, angles));
1789 if(!SV_PushEntity (&trace2, check, move2, true, true))
1791 // entity "check" got teleported
1794 PRVM_serveredictfloat(pusher, solid) = savesolid;
1795 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);
1796 if (trace.startsolid)
1798 // try moving the contacted entity a tiny bit less to account for precision errors
1799 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1800 VectorScale(move, 0.9, move2);
1801 VectorCopy (check->priv.server->moved_from, PRVM_serveredictvector(check, origin));
1802 VectorCopy (check->priv.server->moved_fromangles, PRVM_serveredictvector(check, angles));
1803 if(!SV_PushEntity (&trace2, check, move2, true, true))
1805 // entity "check" got teleported
1808 PRVM_serveredictfloat(pusher, solid) = savesolid;
1809 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
1810 if (trace.startsolid)
1812 // still inside pusher, so it's really blocked
1815 if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1817 if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER)
1820 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1821 VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs));
1825 VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1826 VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1827 PRVM_serveredictfloat(pusher, ltime) = pushltime;
1828 SV_LinkEdict(pusher);
1830 // move back any entities we already moved
1831 for (i = 0;i < num_moved;i++)
1833 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1834 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1835 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
1839 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
1840 if (PRVM_serveredictfunction(pusher, blocked))
1842 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
1843 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
1844 PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
1851 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1852 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1853 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1862 void SV_Physics_Pusher (prvm_edict_t *ent)
1864 float thinktime, oldltime, movetime;
1866 oldltime = PRVM_serveredictfloat(ent, ltime);
1868 thinktime = PRVM_serveredictfloat(ent, nextthink);
1869 if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
1871 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
1876 movetime = sv.frametime;
1879 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
1880 SV_PushMove (ent, movetime);
1882 if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
1884 PRVM_serveredictfloat(ent, nextthink) = 0;
1885 PRVM_serverglobalfloat(time) = sv.time;
1886 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1887 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1888 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1894 ===============================================================================
1898 ===============================================================================
1901 static float unstickoffsets[] =
1903 // poutting -/+z changes first as they are least weird
1918 typedef enum unstickresult_e
1926 unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
1930 // if not stuck in a bmodel, just return
1931 if (!SV_TestEntityPosition(ent, vec3_origin))
1932 return UNSTICK_GOOD;
1934 for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
1936 if (!SV_TestEntityPosition(ent, unstickoffsets + i))
1938 VectorCopy(unstickoffsets + i, offset);
1940 //SV_LinkEdict_TouchAreaGrid(ent);
1941 return UNSTICK_UNSTUCK;
1945 maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
1946 // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
1948 for(i = 2; i <= maxunstick; ++i)
1950 VectorClear(offset);
1952 if (!SV_TestEntityPosition(ent, offset))
1955 //SV_LinkEdict_TouchAreaGrid(ent);
1956 return UNSTICK_UNSTUCK;
1959 if (!SV_TestEntityPosition(ent, offset))
1962 //SV_LinkEdict_TouchAreaGrid(ent);
1963 return UNSTICK_UNSTUCK;
1967 return UNSTICK_STUCK;
1970 qboolean SV_UnstickEntity (prvm_edict_t *ent)
1973 switch(SV_UnstickEntityReturnOffset(ent, offset))
1977 case UNSTICK_UNSTUCK:
1978 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]);
1981 if (developer_extra.integer)
1982 Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1985 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
1994 This is a big hack to try and fix the rare case of getting stuck in the world
1998 void SV_CheckStuck (prvm_edict_t *ent)
2002 switch(SV_UnstickEntityReturnOffset(ent, offset))
2005 VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
2007 case UNSTICK_UNSTUCK:
2008 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]);
2011 VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
2012 if (!SV_TestEntityPosition(ent, offset))
2014 Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2016 //SV_LinkEdict_TouchAreaGrid(ent);
2019 Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2022 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2032 qboolean SV_CheckWater (prvm_edict_t *ent)
2035 int nNativeContents;
2038 point[0] = PRVM_serveredictvector(ent, origin)[0];
2039 point[1] = PRVM_serveredictvector(ent, origin)[1];
2040 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2042 // DRESK - Support for Entity Contents Transition Event
2043 // NOTE: Some logic needed to be slightly re-ordered
2044 // to not affect performance and allow for the feature.
2046 // Acquire Super Contents Prior to Resets
2047 cont = SV_PointSuperContents(point);
2048 // Acquire Native Contents Here
2049 nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
2051 // DRESK - Support for Entity Contents Transition Event
2052 if(PRVM_serveredictfloat(ent, watertype))
2053 // Entity did NOT Spawn; Check
2054 SV_CheckContentsTransition(ent, nNativeContents);
2057 PRVM_serveredictfloat(ent, waterlevel) = 0;
2058 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2059 cont = SV_PointSuperContents(point);
2060 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2062 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2063 PRVM_serveredictfloat(ent, waterlevel) = 1;
2064 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2065 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2067 PRVM_serveredictfloat(ent, waterlevel) = 2;
2068 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2069 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2070 PRVM_serveredictfloat(ent, waterlevel) = 3;
2074 return PRVM_serveredictfloat(ent, waterlevel) > 1;
2083 void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2086 vec3_t forward, into, side;
2088 AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
2089 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2091 // cut the tangential velocity
2092 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2093 VectorScale (stepnormal, i, into);
2094 VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
2095 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2096 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2102 =====================
2105 Player has come to a dead stop, possibly due to the problem with limited
2106 float precision at some angle joins in the BSP hull.
2108 Try fixing by pushing one pixel in each direction.
2110 This is a hack, but in the interest of good gameplay...
2111 ======================
2113 int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2118 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
2121 for (i=0 ; i<8 ; i++)
2123 // try pushing a little in an axial direction
2126 case 0: dir[0] = 2; dir[1] = 0; break;
2127 case 1: dir[0] = 0; dir[1] = 2; break;
2128 case 2: dir[0] = -2; dir[1] = 0; break;
2129 case 3: dir[0] = 0; dir[1] = -2; break;
2130 case 4: dir[0] = 2; dir[1] = 2; break;
2131 case 5: dir[0] = -2; dir[1] = 2; break;
2132 case 6: dir[0] = 2; dir[1] = -2; break;
2133 case 7: dir[0] = -2; dir[1] = -2; break;
2136 SV_PushEntity (&trace, ent, dir, false, true);
2138 // retry the original move
2139 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2140 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2141 PRVM_serveredictvector(ent, velocity)[2] = 0;
2142 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
2144 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2145 || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2147 Con_DPrint("TryUnstick - success.\n");
2151 // go back to the original pos and try again
2152 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
2156 VectorClear (PRVM_serveredictvector(ent, velocity));
2157 Con_DPrint("TryUnstick - failure.\n");
2163 =====================
2166 Only used by players
2167 ======================
2169 void SV_WalkMove (prvm_edict_t *ent)
2173 //int originalmove_clip;
2174 int originalmove_flags;
2175 int originalmove_groundentity;
2176 int hitsupercontentsmask;
2178 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
2179 trace_t downtrace, trace;
2180 qboolean applygravity;
2182 // if frametime is 0 (due to client sending the same timestamp twice),
2184 if (sv.frametime <= 0)
2187 SV_CheckStuck (ent);
2189 applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2191 hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2193 SV_CheckVelocity(ent);
2195 // do a regular slide move unless it looks like you ran into a step
2196 oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2198 VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2199 VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2201 clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2203 if(sv_gameplayfix_downtracesupportsongroundflag.integer)
2206 // only try this if there was no floor in the way in the trace (no,
2207 // this check seems to be not REALLY necessary, because if clip & 1,
2208 // our trace will hit that thing too)
2209 VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
2210 VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
2211 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
2212 type = MOVE_MISSILE;
2213 else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
2214 type = MOVE_NOMONSTERS; // only clip against bmodels
2217 trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
2218 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2219 clip |= 1; // but we HAVE found a floor
2222 // if the move did not hit the ground at any point, we're not on ground
2224 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2226 SV_CheckVelocity(ent);
2228 SV_LinkEdict_TouchAreaGrid(ent);
2230 if(clip & 8) // teleport
2233 if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2236 if (sv_nostep.integer)
2239 VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2240 VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2241 //originalmove_clip = clip;
2242 originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2243 originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2245 // if move didn't block on a step, return
2248 // if move was not trying to move into the step, return
2249 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2252 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
2254 // return if gibbed by a trigger
2255 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
2258 // only step up while jumping if that is enabled
2259 if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
2260 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2264 // try moving up and forward to go up a step
2265 // back to start pos
2266 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2267 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2270 VectorClear (upmove);
2271 upmove[2] = sv_stepheight.value;
2272 if(!SV_PushEntity(&trace, ent, upmove, false, true))
2274 // we got teleported when upstepping... must abort the move
2279 PRVM_serveredictvector(ent, velocity)[2] = 0;
2280 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
2281 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2284 // we got teleported when upstepping... must abort the move
2285 // note that z velocity handling may not be what QC expects here, but we cannot help it
2289 SV_CheckVelocity(ent);
2291 SV_LinkEdict_TouchAreaGrid(ent);
2293 // check for stuckness, possibly due to the limited precision of floats
2294 // in the clipping hulls
2296 && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2297 && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2299 //Con_Printf("wall\n");
2300 // stepping up didn't make any progress, revert to original move
2301 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2302 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2303 //clip = originalmove_clip;
2304 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2305 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2306 // now try to unstick if needed
2307 //clip = SV_TryUnstick (ent, oldvel);
2311 //Con_Printf("step - ");
2313 // extra friction based on view angle
2314 if (clip & 2 && sv_wallfriction.integer)
2315 SV_WallFriction (ent, stepnormal);
2317 // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2318 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))
2322 VectorClear (downmove);
2323 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2324 if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
2326 // we got teleported when downstepping... must abort the move
2330 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2332 // this has been disabled so that you can't jump when you are stepping
2333 // up while already jumping (also known as the Quake2 double jump bug)
2335 // LordHavoc: disabled this check so you can walk on monsters/players
2336 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2338 //Con_Printf("onground\n");
2339 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2340 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
2346 //Con_Printf("slope\n");
2347 // if the push down didn't end up on good ground, use the move without
2348 // the step up. This happens near wall / slope combinations, and can
2349 // cause the player to hop up higher on a slope too steep to climb
2350 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2351 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2352 //clip = originalmove_clip;
2353 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2354 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2357 SV_CheckVelocity(ent);
2359 SV_LinkEdict_TouchAreaGrid(ent);
2362 //============================================================================
2368 Entities that are "stuck" to another entity
2371 void SV_Physics_Follow (prvm_edict_t *ent)
2373 vec3_t vf, vr, vu, angles, v;
2377 if (!SV_RunThink (ent))
2380 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2381 e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
2382 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])
2384 // quick case for no rotation
2385 VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
2389 angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
2390 angles[1] = PRVM_serveredictvector(ent, punchangle)[1];
2391 angles[2] = PRVM_serveredictvector(ent, punchangle)[2];
2392 AngleVectors (angles, vf, vr, vu);
2393 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];
2394 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];
2395 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];
2396 angles[0] = -PRVM_serveredictvector(e, angles)[0];
2397 angles[1] = PRVM_serveredictvector(e, angles)[1];
2398 angles[2] = PRVM_serveredictvector(e, angles)[2];
2399 AngleVectors (angles, vf, vr, vu);
2400 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2401 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2402 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2404 VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
2406 //SV_LinkEdict_TouchAreaGrid(ent);
2410 ==============================================================================
2414 ==============================================================================
2419 SV_CheckWaterTransition
2423 void SV_CheckWaterTransition (prvm_edict_t *ent)
2426 cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
2427 if (!PRVM_serveredictfloat(ent, watertype))
2429 // just spawned here
2430 PRVM_serveredictfloat(ent, watertype) = cont;
2431 PRVM_serveredictfloat(ent, waterlevel) = 1;
2435 // DRESK - Support for Entity Contents Transition Event
2436 // NOTE: Call here BEFORE updating the watertype below,
2437 // and suppress watersplash sound if a valid function
2438 // call was made to allow for custom "splash" sounds.
2439 if( !SV_CheckContentsTransition(ent, cont) )
2440 { // Contents Transition Function Invalid; Potentially Play Water Sound
2441 // check if the entity crossed into or out of water
2442 if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
2443 SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false);
2446 if (cont <= CONTENTS_WATER)
2448 PRVM_serveredictfloat(ent, watertype) = cont;
2449 PRVM_serveredictfloat(ent, waterlevel) = 1;
2453 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2454 PRVM_serveredictfloat(ent, waterlevel) = 0;
2462 Toss, bounce, and fly movement. When onground, do nothing.
2465 void SV_Physics_Toss (prvm_edict_t *ent)
2471 prvm_edict_t *groundentity;
2473 // if onground, return without moving
2474 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2476 groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
2477 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2479 // don't stick to ground if onground and moving upward
2480 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2482 else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
2484 // we can trust FL_ONGROUND if groundentity is world because it never moves
2487 else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
2489 // if ent was supported by a brush model on previous frame,
2490 // and groundentity is now freed, set groundentity to 0 (world)
2491 // which leaves it suspended in the air
2492 PRVM_serveredictedict(ent, groundentity) = 0;
2493 if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
2496 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2498 // don't slide if still touching the groundentity
2502 ent->priv.server->suspendedinairflag = false;
2504 SV_CheckVelocity (ent);
2507 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2508 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
2511 VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2513 movetime = sv.frametime;
2514 for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2517 VectorScale (PRVM_serveredictvector(ent, velocity), movetime, move);
2518 if(!SV_PushEntity (&trace, ent, move, true, true))
2519 return; // teleported
2520 if (ent->priv.server->free)
2522 if (trace.bmodelstartsolid)
2524 // try to unstick the entity
2525 SV_UnstickEntity(ent);
2526 if(!SV_PushEntity (&trace, ent, move, false, true))
2527 return; // teleported
2528 if (ent->priv.server->free)
2531 if (trace.fraction == 1)
2533 movetime *= 1 - min(1, trace.fraction);
2534 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
2537 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2539 bouncefactor = 1.0f;
2541 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2542 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2544 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2546 float d, ent_gravity;
2550 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2552 bouncefactor = 0.5f;
2554 bouncestop = PRVM_serveredictfloat(ent, bouncestop);
2556 bouncestop = 60.0f / 800.0f;
2558 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2559 ent_gravity = PRVM_serveredictfloat(ent, gravity);
2562 // LordHavoc: fixed grenades not bouncing when fired down a slope
2563 if (sv_gameplayfix_grenadebouncedownslopes.integer)
2565 d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
2566 if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
2568 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2569 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2570 VectorClear (PRVM_serveredictvector(ent, velocity));
2571 VectorClear (PRVM_serveredictvector(ent, avelocity));
2574 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2578 if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * bouncestop * ent_gravity)
2580 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2581 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2582 VectorClear (PRVM_serveredictvector(ent, velocity));
2583 VectorClear (PRVM_serveredictvector(ent, avelocity));
2586 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2591 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
2592 if (trace.plane.normal[2] > 0.7)
2594 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2595 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2596 if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
2597 ent->priv.server->suspendedinairflag = true;
2598 VectorClear (PRVM_serveredictvector(ent, velocity));
2599 VectorClear (PRVM_serveredictvector(ent, avelocity));
2602 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2604 if (!sv_gameplayfix_slidemoveprojectiles.integer || (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_BOUNCE && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE) || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2608 // check for in water
2609 SV_CheckWaterTransition (ent);
2613 ===============================================================================
2617 ===============================================================================
2624 Monsters freefall when they don't have a ground entity, otherwise
2625 all movement is done with discrete steps.
2627 This is also used for objects that have become still on the ground, but
2628 will fall if the floor is pulled out from under them.
2631 void SV_Physics_Step (prvm_edict_t *ent)
2633 int flags = (int)PRVM_serveredictfloat(ent, flags);
2636 // Backup Velocity in the event that movetypesteplandevent is called,
2637 // to provide a parameter with the entity's velocity at impact.
2638 vec3_t backupVelocity;
2639 VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2640 // don't fall at all if fly/swim
2641 if (!(flags & (FL_FLY | FL_SWIM)))
2643 if (flags & FL_ONGROUND)
2645 // freefall if onground and moving upward
2646 // freefall if not standing on a world surface (it may be a lift or trap door)
2647 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2649 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2650 SV_CheckVelocity(ent);
2651 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2653 SV_LinkEdict_TouchAreaGrid(ent);
2654 ent->priv.server->waterposition_forceupdate = true;
2659 // freefall if not onground
2660 int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2662 SV_CheckVelocity(ent);
2663 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2665 SV_LinkEdict_TouchAreaGrid(ent);
2668 if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2670 // DRESK - Check for Entity Land Event Function
2671 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2672 { // Valid Function; Execute
2673 // Prepare Parameters
2674 // Assign Velocity at Impact
2675 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2676 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2677 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2679 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2680 // Execute VM Function
2681 PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2684 // Check for Engine Landing Sound
2685 if(sv_sound_land.string)
2686 SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false);
2688 ent->priv.server->waterposition_forceupdate = true;
2693 if (!SV_RunThink(ent))
2696 if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2698 ent->priv.server->waterposition_forceupdate = false;
2699 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2700 SV_CheckWaterTransition(ent);
2704 //============================================================================
2706 static void SV_Physics_Entity (prvm_edict_t *ent)
2708 // don't run think/move on newly spawned projectiles as it messes up
2709 // movement interpolation and rocket trails, and is inconsistent with
2710 // respect to entities spawned in the same frame
2711 // (if an ent spawns a higher numbered ent, it moves in the same frame,
2712 // but if it spawns a lower numbered ent, it doesn't - this never moves
2713 // ents in the first frame regardless)
2714 qboolean runmove = ent->priv.server->move;
2715 ent->priv.server->move = true;
2716 if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2718 switch ((int) PRVM_serveredictfloat(ent, movetype))
2721 case MOVETYPE_FAKEPUSH:
2722 SV_Physics_Pusher (ent);
2725 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2726 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2729 case MOVETYPE_FOLLOW:
2730 SV_Physics_Follow (ent);
2732 case MOVETYPE_NOCLIP:
2733 if (SV_RunThink(ent))
2736 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2737 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2742 SV_Physics_Step (ent);
2745 if (SV_RunThink (ent))
2749 case MOVETYPE_BOUNCE:
2750 case MOVETYPE_BOUNCEMISSILE:
2751 case MOVETYPE_FLYMISSILE:
2754 if (SV_RunThink (ent))
2755 SV_Physics_Toss (ent);
2757 case MOVETYPE_PHYSICS:
2758 if (SV_RunThink(ent))
2761 SV_LinkEdict_TouchAreaGrid(ent);
2765 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2770 void SV_Physics_ClientMove(void)
2773 ent = host_client->edict;
2775 // call player physics, this needs the proper frametime
2776 PRVM_serverglobalfloat(frametime) = sv.frametime;
2779 // call standard client pre-think, with frametime = 0
2780 PRVM_serverglobalfloat(time) = sv.time;
2781 PRVM_serverglobalfloat(frametime) = 0;
2782 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2783 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2784 PRVM_serverglobalfloat(frametime) = sv.frametime;
2786 // make sure the velocity is sane (not a NaN)
2787 SV_CheckVelocity(ent);
2789 // perform MOVETYPE_WALK behavior
2792 // call standard player post-think, with frametime = 0
2793 PRVM_serverglobalfloat(time) = sv.time;
2794 PRVM_serverglobalfloat(frametime) = 0;
2795 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2796 PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2797 PRVM_serverglobalfloat(frametime) = sv.frametime;
2799 if(PRVM_serveredictfloat(ent, fixangle))
2801 // angle fixing was requested by physics code...
2802 // so store the current angles for later use
2803 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2804 host_client->fixangle_angles_set = TRUE;
2806 // and clear fixangle for the next frame
2807 PRVM_serveredictfloat(ent, fixangle) = 0;
2811 static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
2813 // don't do physics on disconnected clients, FrikBot relies on this
2814 if (!host_client->spawned)
2817 // make sure the velocity is sane (not a NaN)
2818 SV_CheckVelocity(ent);
2820 // don't run physics here if running asynchronously
2821 if (host_client->clmovement_inputtimeout <= 0)
2824 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
2827 // make sure the velocity is still sane (not a NaN)
2828 SV_CheckVelocity(ent);
2830 // call standard client pre-think
2831 PRVM_serverglobalfloat(time) = sv.time;
2832 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2833 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2835 // make sure the velocity is still sane (not a NaN)
2836 SV_CheckVelocity(ent);
2839 static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
2841 // don't do physics on disconnected clients, FrikBot relies on this
2842 if (!host_client->spawned)
2845 // make sure the velocity is sane (not a NaN)
2846 SV_CheckVelocity(ent);
2848 // call standard player post-think
2849 PRVM_serverglobalfloat(time) = sv.time;
2850 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2851 PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2853 // make sure the velocity is still sane (not a NaN)
2854 SV_CheckVelocity(ent);
2856 if(PRVM_serveredictfloat(ent, fixangle))
2858 // angle fixing was requested by physics code...
2859 // so store the current angles for later use
2860 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2861 host_client->fixangle_angles_set = TRUE;
2863 // and clear fixangle for the next frame
2864 PRVM_serveredictfloat(ent, fixangle) = 0;
2867 // decrement the countdown variable used to decide when to go back to
2868 // synchronous physics
2869 if (host_client->clmovement_inputtimeout > sv.frametime)
2870 host_client->clmovement_inputtimeout -= sv.frametime;
2872 host_client->clmovement_inputtimeout = 0;
2875 static void SV_Physics_ClientEntity(prvm_edict_t *ent)
2877 // don't do physics on disconnected clients, FrikBot relies on this
2878 if (!host_client->spawned)
2880 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
2884 // make sure the velocity is sane (not a NaN)
2885 SV_CheckVelocity(ent);
2887 switch ((int) PRVM_serveredictfloat(ent, movetype))
2890 case MOVETYPE_FAKEPUSH:
2891 SV_Physics_Pusher (ent);
2894 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2895 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2898 case MOVETYPE_FOLLOW:
2899 SV_Physics_Follow (ent);
2901 case MOVETYPE_NOCLIP:
2904 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2905 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2908 SV_Physics_Step (ent);
2912 // don't run physics here if running asynchronously
2913 if (host_client->clmovement_inputtimeout <= 0)
2917 case MOVETYPE_BOUNCE:
2918 case MOVETYPE_BOUNCEMISSILE:
2919 case MOVETYPE_FLYMISSILE:
2922 SV_Physics_Toss (ent);
2928 case MOVETYPE_PHYSICS:
2932 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2936 SV_CheckVelocity (ent);
2939 SV_LinkEdict_TouchAreaGrid(ent);
2941 SV_CheckVelocity (ent);
2950 void SV_Physics (void)
2955 // let the progs know that a new frame has started
2956 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
2957 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
2958 PRVM_serverglobalfloat(time) = sv.time;
2959 PRVM_serverglobalfloat(frametime) = sv.frametime;
2960 PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
2962 // run physics engine
2963 World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
2966 // treat each object in turn
2969 // if force_retouch, relink all the entities
2970 if (PRVM_serverglobalfloat(force_retouch) > 0)
2971 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
2972 if (!ent->priv.server->free)
2973 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
2975 if (sv_gameplayfix_consistentplayerprethink.integer)
2977 // run physics on the client entities in 3 stages
2978 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
2979 if (!ent->priv.server->free)
2980 SV_Physics_ClientEntity_PreThink(ent);
2982 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
2983 if (!ent->priv.server->free)
2984 SV_Physics_ClientEntity(ent);
2986 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
2987 if (!ent->priv.server->free)
2988 SV_Physics_ClientEntity_PostThink(ent);
2992 // run physics on the client entities
2993 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
2995 if (!ent->priv.server->free)
2997 SV_Physics_ClientEntity_PreThink(ent);
2998 SV_Physics_ClientEntity(ent);
2999 SV_Physics_ClientEntity_PostThink(ent);
3004 // run physics on all the non-client entities
3005 if (!sv_freezenonclients.integer)
3007 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3008 if (!ent->priv.server->free)
3009 SV_Physics_Entity(ent);
3010 // make a second pass to see if any ents spawned this frame and make
3011 // sure they run their move/think
3012 if (sv_gameplayfix_delayprojectiles.integer < 0)
3013 for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3014 if (!ent->priv.server->move && !ent->priv.server->free)
3015 SV_Physics_Entity(ent);
3018 if (PRVM_serverglobalfloat(force_retouch) > 0)
3019 PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
3021 // LordHavoc: endframe support
3022 if (PRVM_serverfunction(EndFrame))
3024 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3025 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3026 PRVM_serverglobalfloat(time) = sv.time;
3027 PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3030 // decrement prog->num_edicts if the highest number entities died
3031 for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3033 if (!sv_freezenonclients.integer)
3034 sv.time += sv.frametime;