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.
23 #include "prvm_cmds.h"
28 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.
30 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
32 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
33 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
34 corpses are SOLID_NOT and MOVETYPE_TOSS
35 crates are SOLID_BBOX and MOVETYPE_TOSS
36 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
37 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
39 solid_edge items only clip against bsp models.
43 #define MOVE_EPSILON 0.01
45 void SV_Physics_Toss (prvm_edict_t *ent);
47 int SV_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent)
51 (model = SV_GetModelFromEdict(ent))
53 model->type == mod_alias
56 (((unsigned char)PRVM_serveredictfloat(ent, pflags)) & PFLAGS_FULLDYNAMIC)
58 ((gamemode == GAME_TENEBRAE) && ((unsigned int)PRVM_serveredictfloat(ent, effects) & (16 | 32)))
66 ===============================================================================
70 ===============================================================================
73 int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
75 prvm_prog_t *prog = SVVM_prog;
78 int dphitcontentsmask = (int)PRVM_serveredictfloat(passedict, dphitcontentsmask);
79 if (dphitcontentsmask)
80 return dphitcontentsmask;
81 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_SLIDEBOX)
83 if ((int)PRVM_serveredictfloat(passedict, flags) & FL_MONSTER)
84 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP;
86 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP;
88 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_CORPSE)
89 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
90 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_TRIGGER)
91 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
93 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
96 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
104 trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
106 prvm_prog_t *prog = SVVM_prog;
107 int i, bodysupercontents;
110 prvm_edict_t *traceowner, *touch;
112 // temporary storage because prvm_vec_t may differ from vec_t
113 vec3_t touchmins, touchmaxs;
114 // bounding box of entire move area
115 vec3_t clipboxmins, clipboxmaxs;
116 // size when clipping against monsters
117 vec3_t clipmins2, clipmaxs2;
118 // start and end origin of move
122 // matrices to transform into/out of other entity's space
123 matrix4x4_t matrix, imatrix;
124 // model of other entity
126 // list of entities to test for collisions
128 static prvm_edict_t *touchedicts[MAX_EDICTS];
130 //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
132 VectorCopy(start, clipstart);
133 VectorClear(clipmins2);
134 VectorClear(clipmaxs2);
135 #if COLLISIONPARANOID >= 3
136 Con_Printf("move(%f %f %f)", clipstart[0], clipstart[1], clipstart[2]);
140 Collision_ClipPointToWorld(&cliptrace, sv.worldmodel, clipstart, hitsupercontentsmask);
141 cliptrace.bmodelstartsolid = cliptrace.startsolid;
142 if (cliptrace.startsolid || cliptrace.fraction < 1)
143 cliptrace.ent = prog->edicts;
144 if (type == MOVE_WORLDONLY)
147 if (type == MOVE_MISSILE)
149 // LordHavoc: modified this, was = -15, now -= 15
150 for (i = 0;i < 3;i++)
157 // create the bounding box of the entire move
158 for (i = 0;i < 3;i++)
160 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
161 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
164 // debug override to test against everything
165 if (sv_debugmove.integer)
167 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
168 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
171 // if the passedict is world, make it NULL (to avoid two checks each time)
172 if (passedict == prog->edicts)
174 // precalculate prog value for passedict for comparisons
175 passedictprog = PRVM_EDICT_TO_PROG(passedict);
176 // precalculate passedict's owner edict pointer for comparisons
177 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
180 // because this uses World_EntitiestoBox, we know all entity boxes overlap
181 // the clip region, so we can skip culling checks in the loop below
182 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
183 if (numtouchedicts > MAX_EDICTS)
185 // this never happens
186 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
187 numtouchedicts = MAX_EDICTS;
189 for (i = 0;i < numtouchedicts;i++)
191 touch = touchedicts[i];
193 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
195 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
200 // don't clip against self
201 if (passedict == touch)
203 // don't clip owned entities against owner
204 if (traceowner == touch)
206 // don't clip owner against owned entities
207 if (passedictprog == PRVM_serveredictedict(touch, owner))
209 // don't clip points against points (they can't collide)
210 if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
214 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
216 // might interact, so do an exact clip
218 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
220 model = SV_GetModelFromEdict(touch);
221 pitchsign = SV_GetPitchSign(prog, touch);
224 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);
226 Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
227 Matrix4x4_Invert_Simple(&imatrix, &matrix);
228 VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
229 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
230 VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
231 VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
232 VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
233 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
234 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
236 Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
238 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
250 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
251 trace_t SV_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
253 trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
256 prvm_prog_t *prog = SVVM_prog;
257 int i, bodysupercontents;
260 prvm_edict_t *traceowner, *touch;
262 // temporary storage because prvm_vec_t may differ from vec_t
263 vec3_t touchmins, touchmaxs;
264 // bounding box of entire move area
265 vec3_t clipboxmins, clipboxmaxs;
266 // size when clipping against monsters
267 vec3_t clipmins2, clipmaxs2;
268 // start and end origin of move
269 vec3_t clipstart, clipend;
272 // matrices to transform into/out of other entity's space
273 matrix4x4_t matrix, imatrix;
274 // model of other entity
276 // list of entities to test for collisions
278 static prvm_edict_t *touchedicts[MAX_EDICTS];
279 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
283 if (VectorCompare(start, pEnd))
284 return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
286 if(collision_endposnudge.value > 0)
288 // TRICK: make the trace 1 qu longer!
289 VectorSubtract(pEnd, start, end);
290 len = VectorNormalizeLength(end);
291 VectorMA(pEnd, collision_endposnudge.value, end, end);
294 VectorCopy(pEnd, end);
296 if (VectorCompare(start, end))
297 return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
300 //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
302 VectorCopy(start, clipstart);
303 VectorCopy(end, clipend);
304 VectorClear(clipmins2);
305 VectorClear(clipmaxs2);
306 #if COLLISIONPARANOID >= 3
307 Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
311 Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, false);
312 cliptrace.bmodelstartsolid = cliptrace.startsolid;
313 if (cliptrace.startsolid || cliptrace.fraction < 1)
314 cliptrace.ent = prog->edicts;
315 if (type == MOVE_WORLDONLY)
318 if (type == MOVE_MISSILE)
320 // LordHavoc: modified this, was = -15, now -= 15
321 for (i = 0;i < 3;i++)
328 // create the bounding box of the entire move
329 for (i = 0;i < 3;i++)
331 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
332 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
335 // debug override to test against everything
336 if (sv_debugmove.integer)
338 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
339 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
342 // if the passedict is world, make it NULL (to avoid two checks each time)
343 if (passedict == prog->edicts)
345 // precalculate prog value for passedict for comparisons
346 passedictprog = PRVM_EDICT_TO_PROG(passedict);
347 // precalculate passedict's owner edict pointer for comparisons
348 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
351 // because this uses World_EntitiestoBox, we know all entity boxes overlap
352 // the clip region, so we can skip culling checks in the loop below
353 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
354 if (numtouchedicts > MAX_EDICTS)
356 // this never happens
357 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
358 numtouchedicts = MAX_EDICTS;
360 for (i = 0;i < numtouchedicts;i++)
362 touch = touchedicts[i];
364 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
366 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
371 // don't clip against self
372 if (passedict == touch)
374 // don't clip owned entities against owner
375 if (traceowner == touch)
377 // don't clip owner against owned entities
378 if (passedictprog == PRVM_serveredictedict(touch, owner))
380 // don't clip points against points (they can't collide)
381 if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
385 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
387 // might interact, so do an exact clip
389 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
391 model = SV_GetModelFromEdict(touch);
392 pitchsign = SV_GetPitchSign(prog, touch);
395 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);
397 Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
398 Matrix4x4_Invert_Simple(&imatrix, &matrix);
399 VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
400 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
401 VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
402 VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
403 VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
404 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
405 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
407 Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false);
409 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
413 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
414 if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
415 Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
425 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
426 #if COLLISIONPARANOID >= 1
427 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)
429 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)
432 #if COLLISIONPARANOID >= 1
433 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)
435 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)
439 prvm_prog_t *prog = SVVM_prog;
440 vec3_t hullmins, hullmaxs;
441 int i, bodysupercontents;
445 prvm_edict_t *traceowner, *touch;
447 // temporary storage because prvm_vec_t may differ from vec_t
448 vec3_t touchmins, touchmaxs;
449 // bounding box of entire move area
450 vec3_t clipboxmins, clipboxmaxs;
451 // size of the moving object
452 vec3_t clipmins, clipmaxs;
453 // size when clipping against monsters
454 vec3_t clipmins2, clipmaxs2;
455 // start and end origin of move
456 vec3_t clipstart, clipend;
459 // matrices to transform into/out of other entity's space
460 matrix4x4_t matrix, imatrix;
461 // model of other entity
463 // list of entities to test for collisions
465 static prvm_edict_t *touchedicts[MAX_EDICTS];
466 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
470 if (VectorCompare(mins, maxs))
472 vec3_t shiftstart, shiftend;
473 VectorAdd(start, mins, shiftstart);
474 VectorAdd(pEnd, mins, shiftend);
475 if (VectorCompare(start, pEnd))
476 trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
478 trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
479 VectorSubtract(trace.endpos, mins, trace.endpos);
483 if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
485 // TRICK: make the trace 1 qu longer!
486 VectorSubtract(pEnd, start, end);
487 len = VectorNormalizeLength(end);
488 VectorMA(pEnd, collision_endposnudge.value, end, end);
491 VectorCopy(pEnd, end);
493 if (VectorCompare(mins, maxs))
495 vec3_t shiftstart, shiftend;
496 VectorAdd(start, mins, shiftstart);
497 VectorAdd(end, mins, shiftend);
498 if (VectorCompare(start, end))
499 trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
501 trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
502 VectorSubtract(trace.endpos, mins, trace.endpos);
507 VectorCopy(start, clipstart);
508 VectorCopy(end, clipend);
509 VectorCopy(mins, clipmins);
510 VectorCopy(maxs, clipmaxs);
511 VectorCopy(mins, clipmins2);
512 VectorCopy(maxs, clipmaxs2);
513 #if COLLISIONPARANOID >= 3
514 Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
518 Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
519 cliptrace.bmodelstartsolid = cliptrace.startsolid;
520 if (cliptrace.startsolid || cliptrace.fraction < 1)
521 cliptrace.ent = prog->edicts;
522 if (type == MOVE_WORLDONLY)
525 if (type == MOVE_MISSILE)
527 // LordHavoc: modified this, was = -15, now -= 15
528 for (i = 0;i < 3;i++)
535 // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
536 if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize)
537 sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs);
540 VectorCopy(clipmins, hullmins);
541 VectorCopy(clipmaxs, hullmaxs);
544 // create the bounding box of the entire move
545 for (i = 0;i < 3;i++)
547 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
548 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
551 // debug override to test against everything
552 if (sv_debugmove.integer)
554 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
555 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
558 // if the passedict is world, make it NULL (to avoid two checks each time)
559 if (passedict == prog->edicts)
561 // precalculate prog value for passedict for comparisons
562 passedictprog = PRVM_EDICT_TO_PROG(passedict);
563 // figure out whether this is a point trace for comparisons
564 pointtrace = VectorCompare(clipmins, clipmaxs);
565 // precalculate passedict's owner edict pointer for comparisons
566 traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
569 // because this uses World_EntitiestoBox, we know all entity boxes overlap
570 // the clip region, so we can skip culling checks in the loop below
571 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
572 if (numtouchedicts > MAX_EDICTS)
574 // this never happens
575 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
576 numtouchedicts = MAX_EDICTS;
578 for (i = 0;i < numtouchedicts;i++)
580 touch = touchedicts[i];
582 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
584 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
589 // don't clip against self
590 if (passedict == touch)
592 // don't clip owned entities against owner
593 if (traceowner == touch)
595 // don't clip owner against owned entities
596 if (passedictprog == PRVM_serveredictedict(touch, owner))
598 // don't clip points against points (they can't collide)
599 if (pointtrace && VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
603 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
605 // might interact, so do an exact clip
607 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
609 model = SV_GetModelFromEdict(touch);
610 pitchsign = SV_GetPitchSign(prog, touch);
613 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);
615 Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
616 Matrix4x4_Invert_Simple(&imatrix, &matrix);
617 VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
618 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
619 VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
620 VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
621 VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
622 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
623 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
625 Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
627 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
631 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
632 if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
633 Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
638 #if COLLISIONPARANOID >= 1
639 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)
644 trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask);
647 VectorCopy(trace.endpos, temp);
648 endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask).startsolid;
649 #if COLLISIONPARANOID < 3
650 if (trace.startsolid || endstuck)
652 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" : "");
658 int SV_PointSuperContents(const vec3_t point)
660 prvm_prog_t *prog = SVVM_prog;
661 int supercontents = 0;
665 // matrices to transform into/out of other entity's space
666 matrix4x4_t matrix, imatrix;
667 // model of other entity
670 // list of entities to test for collisions
672 static prvm_edict_t *touchedicts[MAX_EDICTS];
674 // get world supercontents at this point
675 if (sv.worldmodel && sv.worldmodel->PointSuperContents)
676 supercontents = sv.worldmodel->PointSuperContents(sv.worldmodel, 0, point);
678 // if sv_gameplayfix_swiminbmodels is off we're done
679 if (!sv_gameplayfix_swiminbmodels.integer)
680 return supercontents;
682 // get list of entities at this point
683 numtouchedicts = SV_EntitiesInBox(point, point, MAX_EDICTS, touchedicts);
684 if (numtouchedicts > MAX_EDICTS)
686 // this never happens
687 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
688 numtouchedicts = MAX_EDICTS;
690 for (i = 0;i < numtouchedicts;i++)
692 touch = touchedicts[i];
694 // we only care about SOLID_BSP for pointcontents
695 if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
698 // might interact, so do an exact clip
699 model = SV_GetModelFromEdict(touch);
700 if (!model || !model->PointSuperContents)
702 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);
703 Matrix4x4_Invert_Simple(&imatrix, &matrix);
704 Matrix4x4_Transform(&imatrix, point, transformed);
705 frame = (int)PRVM_serveredictfloat(touch, frame);
706 supercontents |= model->PointSuperContents(model, bound(0, frame, (model->numframes - 1)), transformed);
709 return supercontents;
713 ===============================================================================
715 Linking entities into the world culling system
717 ===============================================================================
720 int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts)
722 prvm_prog_t *prog = SVVM_prog;
723 vec3_t paddedmins, paddedmaxs;
724 if (maxedicts < 1 || resultedicts == NULL)
726 // LordHavoc: discovered this actually causes its own bugs (dm6 teleporters being too close to info_teleport_destination)
727 //VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
728 //VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
729 VectorCopy(mins, paddedmins);
730 VectorCopy(maxs, paddedmaxs);
731 if (sv_areadebug.integer)
733 int numresultedicts = 0;
736 for (edictindex = 1;edictindex < prog->num_edicts;edictindex++)
738 ed = PRVM_EDICT_NUM(edictindex);
739 if (!ed->priv.required->free && BoxesOverlap(PRVM_serveredictvector(ed, absmin), PRVM_serveredictvector(ed, absmax), paddedmins, paddedmaxs))
741 resultedicts[numresultedicts++] = ed;
742 if (numresultedicts == maxedicts)
746 return numresultedicts;
749 return World_EntitiesInBox(&sv.world, paddedmins, paddedmaxs, maxedicts, resultedicts);
752 void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
754 prvm_prog_t *prog = SVVM_prog;
755 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch);
756 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent);
757 PRVM_serverglobalfloat(time) = sv.time;
758 PRVM_serverglobalfloat(trace_allsolid) = false;
759 PRVM_serverglobalfloat(trace_startsolid) = false;
760 PRVM_serverglobalfloat(trace_fraction) = 1;
761 PRVM_serverglobalfloat(trace_inwater) = false;
762 PRVM_serverglobalfloat(trace_inopen) = true;
763 VectorCopy (PRVM_serveredictvector(touch, origin), PRVM_serverglobalvector(trace_endpos));
764 VectorSet (PRVM_serverglobalvector(trace_plane_normal), 0, 0, 1);
765 PRVM_serverglobalfloat(trace_plane_dist) = 0;
766 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(ent);
767 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
768 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
769 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
770 PRVM_serverglobalstring(trace_dphittexturename) = 0;
771 prog->ExecuteProgram(prog, PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
774 void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
776 prvm_prog_t *prog = SVVM_prog;
777 int i, numtouchedicts, old_self, old_other;
779 static prvm_edict_t *touchedicts[MAX_EDICTS];
781 if (ent == prog->edicts)
782 return; // don't add the world
784 if (ent->priv.server->free)
787 if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
790 // build a list of edicts to touch, because the link loop can be corrupted
791 // by IncreaseEdicts called during touch functions
792 numtouchedicts = SV_EntitiesInBox(ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
793 if (numtouchedicts > MAX_EDICTS)
795 // this never happens
796 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
797 numtouchedicts = MAX_EDICTS;
800 old_self = PRVM_serverglobaledict(self);
801 old_other = PRVM_serverglobaledict(other);
802 for (i = 0;i < numtouchedicts;i++)
804 touch = touchedicts[i];
805 if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch))
807 SV_LinkEdict_TouchAreaGrid_Call(touch, ent);
810 PRVM_serverglobaledict(self) = old_self;
811 PRVM_serverglobaledict(other) = old_other;
814 static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
818 Matrix4x4_CreateFromQuakeEntity(&m, 0, 0, 0, angles[PITCH], angles[YAW], angles[ROLL], 1.0);
820 v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
821 VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs);
822 v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
823 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];
824 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];
825 v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
826 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];
827 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];
828 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
829 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];
830 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];
831 v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
832 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];
833 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];
834 v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
835 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];
836 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];
837 v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
838 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];
839 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];
840 v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
841 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];
842 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];
851 void SV_LinkEdict (prvm_edict_t *ent)
853 prvm_prog_t *prog = SVVM_prog;
855 vec3_t mins, maxs, entmins, entmaxs, entangles;
858 if (ent == prog->edicts)
859 return; // don't add the world
861 if (ent->priv.server->free)
864 modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
865 if (modelindex < 0 || modelindex >= MAX_MODELS)
867 Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
870 model = SV_GetModelByIndex(modelindex);
872 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
873 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
874 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
878 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_PHYSICS)
880 // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
881 // TODO special handling for spheres?
882 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
883 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
884 VectorCopy(PRVM_serveredictvector(ent, angles), entangles);
885 RotateBBox(entmins, entmaxs, entangles, mins, maxs);
886 VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins);
887 VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs);
889 else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
893 if (!model->TraceBox)
894 Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
896 if (PRVM_serveredictvector(ent, angles)[0] || PRVM_serveredictvector(ent, angles)[2] || PRVM_serveredictvector(ent, avelocity)[0] || PRVM_serveredictvector(ent, avelocity)[2])
898 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins);
899 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs);
901 else if (PRVM_serveredictvector(ent, angles)[1] || PRVM_serveredictvector(ent, avelocity)[1])
903 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmins, mins);
904 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmaxs, maxs);
908 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins);
909 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs);
914 // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
915 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
916 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
921 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
922 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
926 // to make items easier to pick up and allow them to be grabbed off
927 // of shelves, the abs sizes are expanded
929 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
940 // because movement is clipped an epsilon away from an actual edge,
941 // we must fully check even when bounding boxes don't quite touch
950 VectorCopy(mins, PRVM_serveredictvector(ent, absmin));
951 VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
953 World_LinkEdict(&sv.world, ent, mins, maxs);
957 ===============================================================================
961 ===============================================================================
966 SV_TestEntityPosition
968 returns true if the entity is in solid currently
971 static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
973 prvm_prog_t *prog = SVVM_prog;
975 vec3_t org, entorigin, entmins, entmaxs;
977 contents = SV_GenericHitSuperContentsMask(ent);
978 VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
979 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
980 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
981 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
982 trace = SV_TraceBox(org, entmins, entmaxs, entorigin, ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents);
983 if (trace.startsupercontents & contents)
987 if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs)))
989 // q1bsp/hlbsp use hulls and if the entity does not exactly match
990 // a hull size it is incorrectly tested, so this code tries to
991 // 'fix' it slightly...
992 // FIXME: this breaks entities larger than the hull size
995 VectorAdd(org, entmins, m1);
996 VectorAdd(org, entmaxs, m2);
997 VectorSubtract(m2, m1, s);
998 #define EPSILON (1.0f / 32.0f)
999 if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
1000 if (s[1] >= EPSILON*2) {m1[1] += EPSILON;m2[1] -= EPSILON;}
1001 if (s[2] >= EPSILON*2) {m1[2] += EPSILON;m2[2] -= EPSILON;}
1002 for (i = 0;i < 8;i++)
1004 v[0] = (i & 1) ? m2[0] : m1[0];
1005 v[1] = (i & 2) ? m2[1] : m1[1];
1006 v[2] = (i & 4) ? m2[2] : m1[2];
1007 if (SV_PointSuperContents(v) & contents)
1012 // if the trace found a better position for the entity, move it there
1013 if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001)
1016 // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
1017 VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
1019 // verify if the endpos is REALLY outside solid
1020 VectorCopy(trace.endpos, org);
1021 trace = SV_TraceBox(org, entmins, entmaxs, org, MOVE_NOMONSTERS, ent, contents);
1022 if(trace.startsolid)
1023 Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
1025 VectorCopy(org, PRVM_serveredictvector(ent, origin));
1031 // DRESK - Support for Entity Contents Transition Event
1034 SV_CheckContentsTransition
1036 returns true if entity had a valid contentstransition function call
1039 static int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
1041 prvm_prog_t *prog = SVVM_prog;
1042 int bValidFunctionCall;
1044 // Default Valid Function Call to False
1045 bValidFunctionCall = false;
1047 if(PRVM_serveredictfloat(ent, watertype) != nContents)
1048 { // Changed Contents
1049 // Acquire Contents Transition Function from QC
1050 if(PRVM_serveredictfunction(ent, contentstransition))
1051 { // Valid Function; Execute
1052 // Assign Valid Function
1053 bValidFunctionCall = true;
1054 // Prepare Parameters (Original Contents, New Contents)
1055 // Original Contents
1056 PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
1058 PRVM_G_FLOAT(OFS_PARM1) = nContents;
1060 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1062 PRVM_serverglobalfloat(time) = sv.time;
1063 // Execute VM Function
1064 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
1068 // Return if Function Call was Valid
1069 return bValidFunctionCall;
1078 void SV_CheckVelocity (prvm_edict_t *ent)
1080 prvm_prog_t *prog = SVVM_prog;
1087 for (i=0 ; i<3 ; i++)
1089 if (PRVM_IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
1091 Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
1092 PRVM_serveredictvector(ent, velocity)[i] = 0;
1094 if (PRVM_IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
1096 Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
1097 PRVM_serveredictvector(ent, origin)[i] = 0;
1101 // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
1102 // player_run/player_stand1 does not horribly malfunction if the
1103 // velocity becomes a denormalized float
1104 if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001)
1105 VectorClear(PRVM_serveredictvector(ent, velocity));
1107 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
1108 wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity));
1109 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
1111 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
1112 PRVM_serveredictvector(ent, velocity)[0] *= wishspeed;
1113 PRVM_serveredictvector(ent, velocity)[1] *= wishspeed;
1114 PRVM_serveredictvector(ent, velocity)[2] *= wishspeed;
1122 Runs thinking code if time. There is some play in the exact time the think
1123 function will be called, because it is called before any movement is done
1124 in a frame. Not used for pushmove objects, because they must be exact.
1125 Returns false if the entity removed itself.
1128 static qboolean SV_RunThink (prvm_edict_t *ent)
1130 prvm_prog_t *prog = SVVM_prog;
1133 // don't let things stay in the past.
1134 // it is possible to start that way by a trigger with a local time.
1135 if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime)
1138 for (iterations = 0;iterations < 128 && !ent->priv.server->free;iterations++)
1140 PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink));
1141 PRVM_serveredictfloat(ent, nextthink) = 0;
1142 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1143 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1144 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1145 // mods often set nextthink to time to cause a think every frame,
1146 // we don't want to loop in that case, so exit if the new nextthink is
1147 // <= the time the qc was told, also exit if it is past the end of the
1149 if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
1152 return !ent->priv.server->free;
1159 Two entities have touched, so run their touch functions
1162 static void SV_Impact (prvm_edict_t *e1, trace_t *trace)
1164 prvm_prog_t *prog = SVVM_prog;
1165 int restorevm_tempstringsbuf_cursize;
1166 int old_self, old_other;
1167 prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
1169 old_self = PRVM_serverglobaledict(self);
1170 old_other = PRVM_serverglobaledict(other);
1171 restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1173 VM_SetTraceGlobals(prog, trace);
1175 if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
1177 PRVM_serverglobalfloat(time) = sv.time;
1178 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e1);
1179 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e2);
1180 prog->ExecuteProgram(prog, PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
1183 if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
1185 PRVM_serverglobalfloat(time) = sv.time;
1186 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2);
1187 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1);
1188 VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos));
1189 VectorNegate(trace->plane.normal, PRVM_serverglobalvector(trace_plane_normal));
1190 PRVM_serverglobalfloat(trace_plane_dist) = -trace->plane.dist;
1191 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(e1);
1192 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
1193 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
1194 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
1195 PRVM_serverglobalstring(trace_dphittexturename) = 0;
1196 prog->ExecuteProgram(prog, PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
1199 PRVM_serverglobaledict(self) = old_self;
1200 PRVM_serverglobaledict(other) = old_other;
1201 prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1209 Slide off of the impacting object
1210 returns the blocked flags (1 = floor, 2 = step / wall)
1213 #define STOP_EPSILON 0.1
1214 static void ClipVelocity (prvm_vec3_t in, vec3_t normal, prvm_vec3_t out, prvm_vec_t overbounce)
1219 backoff = -DotProduct (in, normal) * overbounce;
1220 VectorMA(in, backoff, normal, out);
1222 for (i = 0;i < 3;i++)
1223 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
1232 The basic solid body movement clip that slides along multiple planes
1233 Returns the clipflags if the velocity was modified (hit something solid)
1237 8 = teleported by touch method
1238 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
1241 static float SV_Gravity (prvm_edict_t *ent);
1242 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
1243 #define MAX_CLIP_PLANES 5
1244 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask, float stepheight)
1246 prvm_prog_t *prog = SVVM_prog;
1247 int blocked, bumpcount;
1248 int i, j, numplanes;
1249 float d, time_left, gravity;
1250 vec3_t dir, push, planes[MAX_CLIP_PLANES];
1251 prvm_vec3_t primal_velocity, original_velocity, new_velocity, restore_velocity;
1260 VectorCopy(PRVM_serveredictvector(ent, velocity), restore_velocity);
1264 gravity = SV_Gravity(ent);
1266 if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
1268 if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
1269 PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f;
1271 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1276 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1277 VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
1280 for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
1282 if (!PRVM_serveredictvector(ent, velocity)[0] && !PRVM_serveredictvector(ent, velocity)[1] && !PRVM_serveredictvector(ent, velocity)[2])
1285 VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
1286 if(!SV_PushEntity(&trace, ent, push, true, false))
1288 // we got teleported by a touch function
1289 // let's abort the move
1294 // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
1295 // abort move if it started in SUPERCONTENTS_SOLID (not SUPERCONTENTS_BODY used by SOLID_BBOX)
1296 // note the SV_PushEntity call above must pass true for failonbmodelstartsolid
1297 if (trace.allsolid && (trace.startsupercontents & SUPERCONTENTS_SOLID))
1299 VectorCopy(restore_velocity, PRVM_serveredictvector(ent, velocity));
1303 if (trace.fraction == 1)
1305 if (trace.plane.normal[2])
1307 if (trace.plane.normal[2] > 0.7)
1314 Con_Printf ("SV_FlyMove: !trace.ent");
1315 trace.ent = prog->edicts;
1318 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1319 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1322 else if (stepheight)
1324 // step - handle it immediately
1330 //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1331 VectorSet(steppush, 0, 0, stepheight);
1332 VectorCopy(PRVM_serveredictvector(ent, origin), org);
1333 if(!SV_PushEntity(&steptrace, ent, steppush, false, false))
1338 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1339 if(!SV_PushEntity(&steptrace2, ent, push, false, false))
1344 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1345 VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
1346 if(!SV_PushEntity(&steptrace3, ent, steppush, false, false))
1351 //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1352 // accept the new position if it made some progress...
1353 if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
1355 //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]);
1357 VectorCopy(PRVM_serveredictvector(ent, origin), trace.endpos);
1358 time_left *= 1 - trace.fraction;
1364 //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]);
1365 VectorCopy(org, PRVM_serveredictvector(ent, origin));
1370 // step - return it to caller
1372 // save the trace for player extrafriction
1374 VectorCopy(trace.plane.normal, stepnormal);
1376 if (trace.fraction >= 0.001)
1378 // actually covered some distance
1379 VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1383 time_left *= 1 - trace.fraction;
1385 // clipped to another plane
1386 if (numplanes >= MAX_CLIP_PLANES)
1388 // this shouldn't really happen
1389 VectorClear(PRVM_serveredictvector(ent, velocity));
1395 for (i = 0;i < numplanes;i++)
1396 if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
1400 VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity));
1405 VectorCopy(trace.plane.normal, planes[numplanes]);
1408 // modify original_velocity so it parallels all of the clip planes
1409 for (i = 0;i < numplanes;i++)
1411 ClipVelocity(original_velocity, planes[i], new_velocity, 1);
1412 for (j = 0;j < numplanes;j++)
1417 if (DotProduct(new_velocity, planes[j]) < 0)
1427 // go along this plane
1428 VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity));
1432 // go along the crease
1435 VectorClear(PRVM_serveredictvector(ent, velocity));
1439 CrossProduct(planes[0], planes[1], dir);
1440 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
1441 VectorNormalize(dir);
1442 d = DotProduct(dir, PRVM_serveredictvector(ent, velocity));
1443 VectorScale(dir, d, PRVM_serveredictvector(ent, velocity));
1446 // if current velocity is against the original velocity,
1447 // stop dead to avoid tiny occilations in sloping corners
1448 if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0)
1450 VectorClear(PRVM_serveredictvector(ent, velocity));
1455 //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]);
1458 if ((blocked & 1) == 0 && bumpcount > 1)
1460 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
1461 // flag ONGROUND if there's ground under it
1462 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask);
1466 // LordHavoc: this came from QW and allows you to get out of water more easily
1467 if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
1468 VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
1472 if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
1474 if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
1475 PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f;
1488 static float SV_Gravity (prvm_edict_t *ent)
1490 prvm_prog_t *prog = SVVM_prog;
1493 ent_gravity = PRVM_serveredictfloat(ent, gravity);
1496 return ent_gravity * sv_gravity.value * sv.frametime;
1501 ===============================================================================
1505 ===============================================================================
1508 static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
1510 prvm_prog_t *prog = SVVM_prog;
1514 vec3_t stuckmins, stuckmaxs;
1515 vec3_t goodmins, goodmaxs;
1519 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1520 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1521 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1522 VectorCopy(pivot, goodmins);
1523 VectorCopy(pivot, goodmaxs);
1524 for (bump = 0;bump < 6;bump++)
1526 int coord = 2-(bump >> 1);
1527 //int coord = (bump >> 1);
1528 int dir = (bump & 1);
1531 for(subbump = 0; ; ++subbump)
1533 VectorCopy(stuckorigin, testorigin);
1537 testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord];
1542 testorigin[coord] += stuckmins[coord] - goodmins[coord];
1545 stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1546 if (stucktrace.bmodelstartsolid)
1548 // BAD BAD, can't fix that
1552 if (stucktrace.fraction >= 1)
1557 // BAD BAD, can't fix that
1561 // we hit something... let's move out of it
1562 VectorSubtract(stucktrace.endpos, testorigin, move);
1563 nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant
1564 VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin);
1568 Con_Printf("subbump: %d\n", subbump);
1574 goodmaxs[coord] = stuckmaxs[coord];
1579 goodmins[coord] = stuckmins[coord];
1584 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1589 qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
1591 prvm_prog_t *prog = SVVM_prog;
1595 vec3_t stuckmins, stuckmaxs;
1597 vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
1598 if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
1599 separation = 0.0f; // when using hulls, it can not be enlarged
1600 VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1601 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1602 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1603 stuckmins[0] -= separation;
1604 stuckmins[1] -= separation;
1605 stuckmins[2] -= separation;
1606 stuckmaxs[0] += separation;
1607 stuckmaxs[1] += separation;
1608 stuckmaxs[2] += separation;
1609 for (bump = 0;bump < 10;bump++)
1611 stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1612 if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
1614 // found a good location, use it
1615 VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1618 nudge = -stucktrace.startdepth;
1619 VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
1628 Does not change the entities velocity at all
1629 The trace struct is filled with the trace that has been done.
1630 Returns true if the push did not result in the entity being teleported by QC code.
1633 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
1635 prvm_prog_t *prog = SVVM_prog;
1643 solid = (int)PRVM_serveredictfloat(ent, solid);
1644 movetype = (int)PRVM_serveredictfloat(ent, movetype);
1645 VectorCopy(PRVM_serveredictvector(ent, mins), mins);
1646 VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
1648 // move start position out of solids
1649 if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
1651 SV_NudgeOutOfSolid(ent);
1654 VectorCopy(PRVM_serveredictvector(ent, origin), start);
1655 VectorAdd(start, push, end);
1657 if (movetype == MOVETYPE_FLYMISSILE)
1658 type = MOVE_MISSILE;
1659 else if (movetype == MOVETYPE_FLY_WORLDONLY)
1660 type = MOVE_WORLDONLY;
1661 else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
1662 type = MOVE_NOMONSTERS; // only clip against bmodels
1666 *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
1667 if (trace->bmodelstartsolid && failonbmodelstartsolid)
1670 VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
1672 ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
1677 if(!trace->startsolid)
1678 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)
1680 Con_Printf("something eeeeevil happened\n");
1685 SV_LinkEdict_TouchAreaGrid(ent);
1687 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))))
1688 SV_Impact (ent, trace);
1690 if(ent->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT)
1692 ent->priv.required->mark = 0;
1695 else if(ent->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
1697 ent->priv.required->mark = 0;
1702 Con_Printf("The edict mark had been overwritten! Please debug this.\n");
1714 static void SV_PushMove (prvm_edict_t *pusher, float movetime)
1716 prvm_prog_t *prog = SVVM_prog;
1718 int pusherowner, pusherprog;
1721 float savesolid, movetime2, pushltime;
1722 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, pushermins, pushermaxs, checkorigin, checkmins, checkmaxs;
1724 int numcheckentities;
1725 static prvm_edict_t *checkentities[MAX_EDICTS];
1726 dp_model_t *pushermodel;
1727 trace_t trace, trace2;
1728 matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
1729 static unsigned short moved_edicts[MAX_EDICTS];
1732 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])
1734 PRVM_serveredictfloat(pusher, ltime) += movetime;
1738 switch ((int) PRVM_serveredictfloat(pusher, solid))
1740 // LordHavoc: valid pusher types
1743 case SOLID_SLIDEBOX:
1744 case SOLID_CORPSE: // LordHavoc: this would be weird...
1746 // LordHavoc: no collisions
1749 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1750 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1751 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1752 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1753 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1754 PRVM_serveredictfloat(pusher, ltime) += movetime;
1755 SV_LinkEdict(pusher);
1758 Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
1761 index = (int) PRVM_serveredictfloat(pusher, modelindex);
1762 if (index < 1 || index >= MAX_MODELS)
1764 Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
1767 pushermodel = SV_GetModelByIndex(index);
1768 pusherowner = PRVM_serveredictedict(pusher, owner);
1769 pusherprog = PRVM_EDICT_TO_PROG(pusher);
1771 rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0;
1773 movetime2 = movetime;
1774 VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
1775 VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
1776 if (moveangle[0] || moveangle[2])
1778 for (i = 0;i < 3;i++)
1782 mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1783 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1787 mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1788 maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1792 else if (moveangle[1])
1794 for (i = 0;i < 3;i++)
1798 mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1799 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1803 mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1804 maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1810 for (i = 0;i < 3;i++)
1814 mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1815 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1819 mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1820 maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1825 VectorNegate (moveangle, a);
1826 AngleVectorsFLU (a, forward, left, up);
1828 VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
1829 VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
1830 pushltime = PRVM_serveredictfloat(pusher, ltime);
1832 // move the pusher to its final position
1834 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1835 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1836 PRVM_serveredictfloat(pusher, ltime) += movetime;
1837 SV_LinkEdict(pusher);
1839 pushermodel = SV_GetModelFromEdict(pusher);
1840 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);
1841 Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
1843 savesolid = PRVM_serveredictfloat(pusher, solid);
1845 // see if any solid entities are inside the final position
1848 if (PRVM_serveredictfloat(pusher, movetype) == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
1849 numcheckentities = 0;
1850 else // MOVETYPE_PUSH
1851 numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
1852 for (e = 0;e < numcheckentities;e++)
1854 prvm_edict_t *check = checkentities[e];
1855 int movetype = (int)PRVM_serveredictfloat(check, movetype);
1860 case MOVETYPE_FOLLOW:
1861 case MOVETYPE_NOCLIP:
1862 case MOVETYPE_FLY_WORLDONLY:
1868 if (PRVM_serveredictedict(check, owner) == pusherprog)
1871 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1874 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1876 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1877 check->priv.server->waterposition_forceupdate = true;
1879 checkcontents = SV_GenericHitSuperContentsMask(check);
1881 // if the entity is standing on the pusher, it will definitely be moved
1882 // if the entity is not standing on the pusher, but is in the pusher's
1883 // final position, move it
1884 if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
1886 VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins);
1887 VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs);
1888 VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
1889 VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
1890 VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
1891 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents);
1892 //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1893 if (!trace.startsolid)
1895 //Con_Printf("- not in solid\n");
1900 VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot);
1901 //VectorClear(pivot);
1906 VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org);
1907 VectorAdd (org, pivot, org);
1908 org2[0] = DotProduct (org, forward);
1909 org2[1] = DotProduct (org, left);
1910 org2[2] = DotProduct (org, up);
1911 VectorSubtract (org2, org, move);
1912 VectorAdd (move, move1, move);
1915 VectorCopy (move1, move);
1917 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1919 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1920 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1921 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1923 // physics objects need better collisions than this code can do
1924 if (movetype == MOVETYPE_PHYSICS)
1926 VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
1927 SV_LinkEdict(check);
1928 SV_LinkEdict_TouchAreaGrid(check);
1932 // try moving the contacted entity
1933 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1934 if(!SV_PushEntity (&trace, check, move, true, true))
1936 // entity "check" got teleported
1937 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1938 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1939 continue; // pushed enough
1941 // FIXME: turn players specially
1942 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1943 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1944 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1946 // this trace.fraction < 1 check causes items to fall off of pushers
1947 // if they pass under or through a wall
1948 // the groundentity check causes items to fall off of ledges
1949 if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
1950 PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1952 // if it is still inside the pusher, block
1953 VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins);
1954 VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs);
1955 VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
1956 VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
1957 VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
1958 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents);
1959 if (trace.startsolid)
1962 if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
1964 // hack to invoke all necessary movement triggers
1966 if(!SV_PushEntity(&trace2, check, move2, true, true))
1968 // entity "check" got teleported
1975 // still inside pusher, so it's really blocked
1978 if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1980 if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER)
1983 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1984 VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs));
1988 VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1989 VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1990 PRVM_serveredictfloat(pusher, ltime) = pushltime;
1991 SV_LinkEdict(pusher);
1993 // move back any entities we already moved
1994 for (i = 0;i < num_moved;i++)
1996 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1997 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1998 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
2002 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
2003 if (PRVM_serveredictfunction(pusher, blocked))
2005 PRVM_serverglobalfloat(time) = sv.time;
2006 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
2007 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
2008 prog->ExecuteProgram(prog, PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
2013 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
2014 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
2015 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
2024 static void SV_Physics_Pusher (prvm_edict_t *ent)
2026 prvm_prog_t *prog = SVVM_prog;
2027 float thinktime, oldltime, movetime;
2029 oldltime = PRVM_serveredictfloat(ent, ltime);
2031 thinktime = PRVM_serveredictfloat(ent, nextthink);
2032 if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
2034 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
2039 movetime = sv.frametime;
2042 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
2043 SV_PushMove (ent, movetime);
2045 if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
2047 PRVM_serveredictfloat(ent, nextthink) = 0;
2048 PRVM_serverglobalfloat(time) = sv.time;
2049 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2050 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
2051 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
2057 ===============================================================================
2061 ===============================================================================
2064 static float unstickoffsets[] =
2066 // poutting -/+z changes first as they are least weird
2081 typedef enum unstickresult_e
2089 static unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
2091 prvm_prog_t *prog = SVVM_prog;
2094 // if not stuck in a bmodel, just return
2095 if (!SV_TestEntityPosition(ent, vec3_origin))
2096 return UNSTICK_GOOD;
2098 for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
2100 if (!SV_TestEntityPosition(ent, unstickoffsets + i))
2102 VectorCopy(unstickoffsets + i, offset);
2104 //SV_LinkEdict_TouchAreaGrid(ent);
2105 return UNSTICK_UNSTUCK;
2109 maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
2110 // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
2112 for(i = 2; i <= maxunstick; ++i)
2114 VectorClear(offset);
2116 if (!SV_TestEntityPosition(ent, offset))
2119 //SV_LinkEdict_TouchAreaGrid(ent);
2120 return UNSTICK_UNSTUCK;
2123 if (!SV_TestEntityPosition(ent, offset))
2126 //SV_LinkEdict_TouchAreaGrid(ent);
2127 return UNSTICK_UNSTUCK;
2131 return UNSTICK_STUCK;
2134 qboolean SV_UnstickEntity (prvm_edict_t *ent)
2136 prvm_prog_t *prog = SVVM_prog;
2138 switch(SV_UnstickEntityReturnOffset(ent, offset))
2142 case UNSTICK_UNSTUCK:
2143 Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
2146 if (developer_extra.integer)
2147 Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
2150 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2159 This is a big hack to try and fix the rare case of getting stuck in the world
2163 static void SV_CheckStuck (prvm_edict_t *ent)
2165 prvm_prog_t *prog = SVVM_prog;
2168 switch(SV_UnstickEntityReturnOffset(ent, offset))
2171 VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
2173 case UNSTICK_UNSTUCK:
2174 Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
2177 VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
2178 if (!SV_TestEntityPosition(ent, offset))
2180 Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
2182 //SV_LinkEdict_TouchAreaGrid(ent);
2185 Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
2188 Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2198 static qboolean SV_CheckWater (prvm_edict_t *ent)
2200 prvm_prog_t *prog = SVVM_prog;
2202 int nNativeContents;
2205 point[0] = PRVM_serveredictvector(ent, origin)[0];
2206 point[1] = PRVM_serveredictvector(ent, origin)[1];
2207 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2209 // DRESK - Support for Entity Contents Transition Event
2210 // NOTE: Some logic needed to be slightly re-ordered
2211 // to not affect performance and allow for the feature.
2213 // Acquire Super Contents Prior to Resets
2214 cont = SV_PointSuperContents(point);
2215 // Acquire Native Contents Here
2216 nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
2218 // DRESK - Support for Entity Contents Transition Event
2219 if(PRVM_serveredictfloat(ent, watertype))
2220 // Entity did NOT Spawn; Check
2221 SV_CheckContentsTransition(ent, nNativeContents);
2224 PRVM_serveredictfloat(ent, waterlevel) = 0;
2225 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2226 cont = SV_PointSuperContents(point);
2227 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2229 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2230 PRVM_serveredictfloat(ent, waterlevel) = 1;
2231 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2232 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2234 PRVM_serveredictfloat(ent, waterlevel) = 2;
2235 point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2236 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2237 PRVM_serveredictfloat(ent, waterlevel) = 3;
2241 return PRVM_serveredictfloat(ent, waterlevel) > 1;
2250 static void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2252 prvm_prog_t *prog = SVVM_prog;
2254 vec3_t forward, into, side, v_angle;
2256 VectorCopy(PRVM_serveredictvector(ent, v_angle), v_angle);
2257 AngleVectors (v_angle, forward, NULL, NULL);
2258 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2260 // cut the tangential velocity
2261 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2262 VectorScale (stepnormal, i, into);
2263 VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
2264 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2265 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2271 =====================
2274 Player has come to a dead stop, possibly due to the problem with limited
2275 float precision at some angle joins in the BSP hull.
2277 Try fixing by pushing one pixel in each direction.
2279 This is a hack, but in the interest of good gameplay...
2280 ======================
2282 int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2287 VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
2290 for (i=0 ; i<8 ; i++)
2292 // try pushing a little in an axial direction
2295 case 0: dir[0] = 2; dir[1] = 0; break;
2296 case 1: dir[0] = 0; dir[1] = 2; break;
2297 case 2: dir[0] = -2; dir[1] = 0; break;
2298 case 3: dir[0] = 0; dir[1] = -2; break;
2299 case 4: dir[0] = 2; dir[1] = 2; break;
2300 case 5: dir[0] = -2; dir[1] = 2; break;
2301 case 6: dir[0] = 2; dir[1] = -2; break;
2302 case 7: dir[0] = -2; dir[1] = -2; break;
2305 SV_PushEntity (&trace, ent, dir, false, true);
2307 // retry the original move
2308 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2309 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2310 PRVM_serveredictvector(ent, velocity)[2] = 0;
2311 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
2313 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2314 || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2316 Con_DPrint("TryUnstick - success.\n");
2320 // go back to the original pos and try again
2321 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
2325 VectorClear (PRVM_serveredictvector(ent, velocity));
2326 Con_DPrint("TryUnstick - failure.\n");
2332 =====================
2335 Only used by players
2336 ======================
2338 static void SV_WalkMove (prvm_edict_t *ent)
2340 prvm_prog_t *prog = SVVM_prog;
2343 //int originalmove_clip;
2344 int originalmove_flags;
2345 int originalmove_groundentity;
2346 int hitsupercontentsmask;
2348 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity, entmins, entmaxs;
2349 trace_t downtrace, trace;
2350 qboolean applygravity;
2352 // if frametime is 0 (due to client sending the same timestamp twice),
2354 if (sv.frametime <= 0)
2357 if (sv_gameplayfix_unstickplayers.integer)
2358 SV_CheckStuck (ent);
2360 applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2362 hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2364 SV_CheckVelocity(ent);
2366 // do a regular slide move unless it looks like you ran into a step
2367 oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2369 VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2370 VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2372 clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2374 if(sv_gameplayfix_downtracesupportsongroundflag.integer)
2377 // only try this if there was no floor in the way in the trace (no,
2378 // this check seems to be not REALLY necessary, because if clip & 1,
2379 // our trace will hit that thing too)
2380 VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
2381 VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
2382 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
2383 type = MOVE_MISSILE;
2384 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY)
2385 type = MOVE_WORLDONLY;
2386 else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
2387 type = MOVE_NOMONSTERS; // only clip against bmodels
2390 VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
2391 VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
2392 trace = SV_TraceBox(upmove, entmins, entmaxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
2393 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2394 clip |= 1; // but we HAVE found a floor
2397 // if the move did not hit the ground at any point, we're not on ground
2399 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2401 SV_CheckVelocity(ent);
2403 SV_LinkEdict_TouchAreaGrid(ent);
2405 if(clip & 8) // teleport
2408 if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2411 if (sv_nostep.integer)
2414 VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2415 VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2416 //originalmove_clip = clip;
2417 originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2418 originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2420 // if move didn't block on a step, return
2423 // if move was not trying to move into the step, return
2424 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2427 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
2429 // return if gibbed by a trigger
2430 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
2433 // only step up while jumping if that is enabled
2434 if (sv_jumpstep.integer)
2435 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2439 // try moving up and forward to go up a step
2440 // back to start pos
2441 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2442 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2445 VectorClear (upmove);
2446 upmove[2] = sv_stepheight.value;
2447 if(!SV_PushEntity(&trace, ent, upmove, false, true))
2449 // we got teleported when upstepping... must abort the move
2454 PRVM_serveredictvector(ent, velocity)[2] = 0;
2455 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
2456 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2459 // we got teleported when upstepping... must abort the move
2460 // note that z velocity handling may not be what QC expects here, but we cannot help it
2464 SV_CheckVelocity(ent);
2466 SV_LinkEdict_TouchAreaGrid(ent);
2468 // check for stuckness, possibly due to the limited precision of floats
2469 // in the clipping hulls
2471 && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2472 && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2474 //Con_Printf("wall\n");
2475 // stepping up didn't make any progress, revert to original move
2476 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2477 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2478 //clip = originalmove_clip;
2479 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2480 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2481 // now try to unstick if needed
2482 //clip = SV_TryUnstick (ent, oldvel);
2486 //Con_Printf("step - ");
2488 // extra friction based on view angle
2489 if (clip & 2 && sv_wallfriction.integer)
2490 SV_WallFriction (ent, stepnormal);
2492 // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2493 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))
2497 VectorClear (downmove);
2498 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2499 if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
2501 // we got teleported when downstepping... must abort the move
2505 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2507 // this has been disabled so that you can't jump when you are stepping
2508 // up while already jumping (also known as the Quake2 double jump bug)
2510 // LordHavoc: disabled this check so you can walk on monsters/players
2511 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2513 //Con_Printf("onground\n");
2514 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2515 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
2521 //Con_Printf("slope\n");
2522 // if the push down didn't end up on good ground, use the move without
2523 // the step up. This happens near wall / slope combinations, and can
2524 // cause the player to hop up higher on a slope too steep to climb
2525 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2526 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2527 //clip = originalmove_clip;
2528 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2529 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2532 SV_CheckVelocity(ent);
2534 SV_LinkEdict_TouchAreaGrid(ent);
2537 //============================================================================
2543 Entities that are "stuck" to another entity
2546 static void SV_Physics_Follow (prvm_edict_t *ent)
2548 prvm_prog_t *prog = SVVM_prog;
2549 vec3_t vf, vr, vu, angles, v;
2553 if (!SV_RunThink (ent))
2556 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2557 e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
2558 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])
2560 // quick case for no rotation
2561 VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
2565 angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
2566 angles[1] = PRVM_serveredictvector(ent, punchangle)[1];
2567 angles[2] = PRVM_serveredictvector(ent, punchangle)[2];
2568 AngleVectors (angles, vf, vr, vu);
2569 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];
2570 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];
2571 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];
2572 angles[0] = -PRVM_serveredictvector(e, angles)[0];
2573 angles[1] = PRVM_serveredictvector(e, angles)[1];
2574 angles[2] = PRVM_serveredictvector(e, angles)[2];
2575 AngleVectors (angles, vf, vr, vu);
2576 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2577 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2578 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2580 VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
2582 //SV_LinkEdict_TouchAreaGrid(ent);
2586 ==============================================================================
2590 ==============================================================================
2595 SV_CheckWaterTransition
2599 static void SV_CheckWaterTransition (prvm_edict_t *ent)
2602 prvm_prog_t *prog = SVVM_prog;
2603 // LordHavoc: bugfixes in this function are keyed to the sv_gameplayfix_bugfixedcheckwatertransition cvar - if this cvar is 0 then all the original bugs should be reenabled for compatibility
2605 VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
2606 cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(entorigin));
2607 if (!PRVM_serveredictfloat(ent, watertype))
2609 // just spawned here
2610 if (!sv_gameplayfix_fixedcheckwatertransition.integer)
2612 PRVM_serveredictfloat(ent, watertype) = cont;
2613 PRVM_serveredictfloat(ent, waterlevel) = 1;
2617 // DRESK - Support for Entity Contents Transition Event
2618 // NOTE: Call here BEFORE updating the watertype below,
2619 // and suppress watersplash sound if a valid function
2620 // call was made to allow for custom "splash" sounds.
2621 else if( !SV_CheckContentsTransition(ent, cont) )
2622 { // Contents Transition Function Invalid; Potentially Play Water Sound
2623 // check if the entity crossed into or out of water
2624 if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
2625 SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false, 1.0f);
2628 if (cont <= CONTENTS_WATER)
2630 PRVM_serveredictfloat(ent, watertype) = cont;
2631 PRVM_serveredictfloat(ent, waterlevel) = 1;
2635 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2636 PRVM_serveredictfloat(ent, waterlevel) = sv_gameplayfix_fixedcheckwatertransition.integer ? 0 : cont;
2644 Toss, bounce, and fly movement. When onground, do nothing.
2648 void SV_Physics_Toss (prvm_edict_t *ent)
2650 prvm_prog_t *prog = SVVM_prog;
2655 prvm_edict_t *groundentity;
2656 float d, ent_gravity;
2660 // if onground, return without moving
2661 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2663 groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
2664 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2666 // don't stick to ground if onground and moving upward
2667 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2669 else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
2671 // we can trust FL_ONGROUND if groundentity is world because it never moves
2674 else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
2676 // if ent was supported by a brush model on previous frame,
2677 // and groundentity is now freed, set groundentity to 0 (world)
2678 // which leaves it suspended in the air
2679 PRVM_serveredictedict(ent, groundentity) = 0;
2680 if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
2683 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2685 // don't slide if still touching the groundentity
2689 ent->priv.server->suspendedinairflag = false;
2691 SV_CheckVelocity (ent);
2694 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2695 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
2698 VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2700 movetime = sv.frametime;
2701 for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2704 VectorScale(PRVM_serveredictvector(ent, velocity), movetime, move);
2705 if(!SV_PushEntity(&trace, ent, move, true, true))
2706 return; // teleported
2707 if (ent->priv.server->free)
2709 if (trace.bmodelstartsolid)
2711 // try to unstick the entity
2712 if (sv_gameplayfix_unstickentities.integer)
2713 SV_UnstickEntity(ent);
2714 if(!SV_PushEntity(&trace, ent, move, false, true))
2715 return; // teleported
2716 if (ent->priv.server->free)
2719 if (trace.fraction == 1)
2721 movetime *= 1 - min(1, trace.fraction);
2722 switch((int)PRVM_serveredictfloat(ent, movetype))
2724 case MOVETYPE_BOUNCEMISSILE:
2725 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2727 bouncefactor = 1.0f;
2729 ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2730 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2731 if (!sv_gameplayfix_slidemoveprojectiles.integer)
2734 case MOVETYPE_BOUNCE:
2735 bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2737 bouncefactor = 0.5f;
2739 bouncestop = PRVM_serveredictfloat(ent, bouncestop);
2741 bouncestop = 60.0f / 800.0f;
2743 ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2744 ent_gravity = PRVM_serveredictfloat(ent, gravity);
2747 // LordHavoc: fixed grenades not bouncing when fired down a slope
2748 if (sv_gameplayfix_grenadebouncedownslopes.integer)
2749 d = fabs(DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity)));
2751 d = PRVM_serveredictvector(ent, velocity)[2];
2752 if (trace.plane.normal[2] > 0.7 && d < sv_gravity.value * bouncestop * ent_gravity)
2754 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2755 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2756 VectorClear(PRVM_serveredictvector(ent, velocity));
2757 VectorClear(PRVM_serveredictvector(ent, avelocity));
2762 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2763 if (!sv_gameplayfix_slidemoveprojectiles.integer)
2768 ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
2769 if (trace.plane.normal[2] > 0.7)
2771 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2772 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2773 if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
2774 ent->priv.server->suspendedinairflag = true;
2775 VectorClear (PRVM_serveredictvector(ent, velocity));
2776 VectorClear (PRVM_serveredictvector(ent, avelocity));
2779 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2785 // check for in water
2786 SV_CheckWaterTransition (ent);
2790 ===============================================================================
2794 ===============================================================================
2801 Monsters freefall when they don't have a ground entity, otherwise
2802 all movement is done with discrete steps.
2804 This is also used for objects that have become still on the ground, but
2805 will fall if the floor is pulled out from under them.
2808 static void SV_Physics_Step (prvm_edict_t *ent)
2810 prvm_prog_t *prog = SVVM_prog;
2811 int flags = (int)PRVM_serveredictfloat(ent, flags);
2814 // Backup Velocity in the event that movetypesteplandevent is called,
2815 // to provide a parameter with the entity's velocity at impact.
2816 vec3_t backupVelocity;
2817 VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2818 // don't fall at all if fly/swim
2819 if (!(flags & (FL_FLY | FL_SWIM)))
2821 if (flags & FL_ONGROUND)
2823 // freefall if onground and moving upward
2824 // freefall if not standing on a world surface (it may be a lift or trap door)
2825 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2827 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2828 SV_CheckVelocity(ent);
2829 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2831 SV_LinkEdict_TouchAreaGrid(ent);
2832 ent->priv.server->waterposition_forceupdate = true;
2837 // freefall if not onground
2838 int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2840 SV_CheckVelocity(ent);
2841 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2843 SV_LinkEdict_TouchAreaGrid(ent);
2846 if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2848 // DRESK - Check for Entity Land Event Function
2849 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2850 { // Valid Function; Execute
2851 // Prepare Parameters
2852 // Assign Velocity at Impact
2853 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2854 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2855 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2857 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2859 PRVM_serverglobalfloat(time) = sv.time;
2860 // Execute VM Function
2861 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2864 // Check for Engine Landing Sound
2865 if(sv_sound_land.string)
2866 SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false, 1.0f);
2868 ent->priv.server->waterposition_forceupdate = true;
2873 if (!SV_RunThink(ent))
2876 if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2878 ent->priv.server->waterposition_forceupdate = false;
2879 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2880 SV_CheckWaterTransition(ent);
2884 //============================================================================
2886 static void SV_Physics_Entity (prvm_edict_t *ent)
2888 prvm_prog_t *prog = SVVM_prog;
2889 // don't run think/move on newly spawned projectiles as it messes up
2890 // movement interpolation and rocket trails, and is inconsistent with
2891 // respect to entities spawned in the same frame
2892 // (if an ent spawns a higher numbered ent, it moves in the same frame,
2893 // but if it spawns a lower numbered ent, it doesn't - this never moves
2894 // ents in the first frame regardless)
2895 qboolean runmove = ent->priv.server->move;
2896 ent->priv.server->move = true;
2897 if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2899 switch ((int) PRVM_serveredictfloat(ent, movetype))
2902 case MOVETYPE_FAKEPUSH:
2903 SV_Physics_Pusher (ent);
2906 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2907 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2910 case MOVETYPE_FOLLOW:
2911 SV_Physics_Follow (ent);
2913 case MOVETYPE_NOCLIP:
2914 if (SV_RunThink(ent))
2917 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2918 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2923 SV_Physics_Step (ent);
2926 if (SV_RunThink (ent))
2930 case MOVETYPE_BOUNCE:
2931 case MOVETYPE_BOUNCEMISSILE:
2932 case MOVETYPE_FLYMISSILE:
2934 case MOVETYPE_FLY_WORLDONLY:
2936 if (SV_RunThink (ent))
2937 SV_Physics_Toss (ent);
2939 case MOVETYPE_PHYSICS:
2940 if (SV_RunThink(ent))
2943 SV_LinkEdict_TouchAreaGrid(ent);
2947 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2952 void SV_Physics_ClientMove(void)
2954 prvm_prog_t *prog = SVVM_prog;
2956 ent = host_client->edict;
2958 // call player physics, this needs the proper frametime
2959 PRVM_serverglobalfloat(frametime) = sv.frametime;
2962 // call standard client pre-think, with frametime = 0
2963 PRVM_serverglobalfloat(time) = sv.time;
2964 PRVM_serverglobalfloat(frametime) = 0;
2965 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2966 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2967 PRVM_serverglobalfloat(frametime) = sv.frametime;
2969 // make sure the velocity is sane (not a NaN)
2970 SV_CheckVelocity(ent);
2972 // perform MOVETYPE_WALK behavior
2975 // call standard player post-think, with frametime = 0
2976 PRVM_serverglobalfloat(time) = sv.time;
2977 PRVM_serverglobalfloat(frametime) = 0;
2978 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2979 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2980 PRVM_serverglobalfloat(frametime) = sv.frametime;
2982 if(PRVM_serveredictfloat(ent, fixangle))
2984 // angle fixing was requested by physics code...
2985 // so store the current angles for later use
2986 VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles);
2987 host_client->fixangle_angles_set = TRUE;
2989 // and clear fixangle for the next frame
2990 PRVM_serveredictfloat(ent, fixangle) = 0;
2994 static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
2996 prvm_prog_t *prog = SVVM_prog;
2997 // don't do physics on disconnected clients, FrikBot relies on this
2998 if (!host_client->begun)
3001 // make sure the velocity is sane (not a NaN)
3002 SV_CheckVelocity(ent);
3004 // don't run physics here if running asynchronously
3005 if (host_client->clmovement_inputtimeout <= 0)
3008 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
3011 // make sure the velocity is still sane (not a NaN)
3012 SV_CheckVelocity(ent);
3014 // call standard client pre-think
3015 PRVM_serverglobalfloat(time) = sv.time;
3016 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
3017 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
3019 // make sure the velocity is still sane (not a NaN)
3020 SV_CheckVelocity(ent);
3023 static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
3025 prvm_prog_t *prog = SVVM_prog;
3026 // don't do physics on disconnected clients, FrikBot relies on this
3027 if (!host_client->begun)
3030 // make sure the velocity is sane (not a NaN)
3031 SV_CheckVelocity(ent);
3033 // call standard player post-think
3034 PRVM_serverglobalfloat(time) = sv.time;
3035 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
3036 prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
3038 // make sure the velocity is still sane (not a NaN)
3039 SV_CheckVelocity(ent);
3041 if(PRVM_serveredictfloat(ent, fixangle))
3043 // angle fixing was requested by physics code...
3044 // so store the current angles for later use
3045 VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles);
3046 host_client->fixangle_angles_set = TRUE;
3048 // and clear fixangle for the next frame
3049 PRVM_serveredictfloat(ent, fixangle) = 0;
3052 // decrement the countdown variable used to decide when to go back to
3053 // synchronous physics
3054 if (host_client->clmovement_inputtimeout > sv.frametime)
3055 host_client->clmovement_inputtimeout -= sv.frametime;
3057 host_client->clmovement_inputtimeout = 0;
3060 static void SV_Physics_ClientEntity(prvm_edict_t *ent)
3062 prvm_prog_t *prog = SVVM_prog;
3063 // don't do physics on disconnected clients, FrikBot relies on this
3064 if (!host_client->begun)
3066 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
3070 // make sure the velocity is sane (not a NaN)
3071 SV_CheckVelocity(ent);
3073 switch ((int) PRVM_serveredictfloat(ent, movetype))
3076 case MOVETYPE_FAKEPUSH:
3077 SV_Physics_Pusher (ent);
3080 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
3081 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
3084 case MOVETYPE_FOLLOW:
3085 SV_Physics_Follow (ent);
3087 case MOVETYPE_NOCLIP:
3090 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
3091 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
3094 SV_Physics_Step (ent);
3098 // don't run physics here if running asynchronously
3099 if (host_client->clmovement_inputtimeout <= 0)
3103 case MOVETYPE_BOUNCE:
3104 case MOVETYPE_BOUNCEMISSILE:
3105 case MOVETYPE_FLYMISSILE:
3108 SV_Physics_Toss (ent);
3111 case MOVETYPE_FLY_WORLDONLY:
3115 case MOVETYPE_PHYSICS:
3119 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
3123 SV_CheckVelocity (ent);
3126 SV_LinkEdict_TouchAreaGrid(ent);
3128 SV_CheckVelocity (ent);
3137 void SV_Physics (void)
3139 prvm_prog_t *prog = SVVM_prog;
3143 // let the progs know that a new frame has started
3144 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3145 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3146 PRVM_serverglobalfloat(time) = sv.time;
3147 PRVM_serverglobalfloat(frametime) = sv.frametime;
3148 prog->ExecuteProgram(prog, PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
3150 // run physics engine
3151 World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
3154 // treat each object in turn
3157 // if force_retouch, relink all the entities
3158 if (PRVM_serverglobalfloat(force_retouch) > 0)
3159 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3160 if (!ent->priv.server->free)
3161 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
3163 if (sv_gameplayfix_consistentplayerprethink.integer)
3165 // run physics on the client entities in 3 stages
3166 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3167 if (!ent->priv.server->free)
3168 SV_Physics_ClientEntity_PreThink(ent);
3170 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3171 if (!ent->priv.server->free)
3172 SV_Physics_ClientEntity(ent);
3174 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3175 if (!ent->priv.server->free)
3176 SV_Physics_ClientEntity_PostThink(ent);
3180 // run physics on the client entities
3181 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3183 if (!ent->priv.server->free)
3185 SV_Physics_ClientEntity_PreThink(ent);
3186 SV_Physics_ClientEntity(ent);
3187 SV_Physics_ClientEntity_PostThink(ent);
3192 // run physics on all the non-client entities
3193 if (!sv_freezenonclients.integer)
3195 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3196 if (!ent->priv.server->free)
3197 SV_Physics_Entity(ent);
3198 // make a second pass to see if any ents spawned this frame and make
3199 // sure they run their move/think
3200 if (sv_gameplayfix_delayprojectiles.integer < 0)
3201 for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3202 if (!ent->priv.server->move && !ent->priv.server->free)
3203 SV_Physics_Entity(ent);
3206 if (PRVM_serverglobalfloat(force_retouch) > 0)
3207 PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
3209 // LordHavoc: endframe support
3210 if (PRVM_serverfunction(EndFrame))
3212 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3213 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3214 PRVM_serverglobalfloat(time) = sv.time;
3215 prog->ExecuteProgram(prog, PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3218 // decrement prog->num_edicts if the highest number entities died
3219 for (;PRVM_ED_CanAlloc(prog, PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3221 if (!sv_freezenonclients.integer)
3222 sv.time += sv.frametime;