+ // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
+ if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize)
+ sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs);
+ else
+ {
+ VectorCopy(clipmins, hullmins);
+ VectorCopy(clipmaxs, hullmaxs);
+ }
+
+ // create the bounding box of the entire move
+ for (i = 0;i < 3;i++)
+ {
+ clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
+ clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
+ }
+
+ // debug override to test against everything
+ if (sv_debugmove.integer)
+ {
+ clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
+ clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
+ }
+
+ // if the passedict is world, make it NULL (to avoid two checks each time)
+ if (passedict == prog->edicts)
+ passedict = NULL;
+ // precalculate prog value for passedict for comparisons
+ passedictprog = PRVM_EDICT_TO_PROG(passedict);
+ // figure out whether this is a point trace for comparisons
+ pointtrace = VectorCompare(clipmins, clipmaxs);
+ // precalculate passedict's owner edict pointer for comparisons
+ traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.server->owner) : 0;
+
+ // clip to entities
+ // because this uses World_EntitiestoBox, we know all entity boxes overlap
+ // the clip region, so we can skip culling checks in the loop below
+ numtouchedicts = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+ if (numtouchedicts > MAX_EDICTS)
+ {
+ // this never happens
+ Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
+ numtouchedicts = MAX_EDICTS;
+ }
+ for (i = 0;i < numtouchedicts;i++)
+ {
+ touch = touchedicts[i];
+
+ if (touch->fields.server->solid < SOLID_BBOX)
+ continue;
+ if (type == MOVE_NOMONSTERS && touch->fields.server->solid != SOLID_BSP)
+ continue;
+
+ if (passedict)
+ {
+ // don't clip against self
+ if (passedict == touch)
+ continue;
+ // don't clip owned entities against owner
+ if (traceowner == touch)
+ continue;
+ // don't clip owner against owned entities
+ if (passedictprog == touch->fields.server->owner)
+ continue;
+ // don't clip points against points (they can't collide)
+ if (pointtrace && VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER)))
+ continue;
+ }
+
+ bodysupercontents = touch->fields.server->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
+
+ // might interact, so do an exact clip
+ model = NULL;
+ if ((int) touch->fields.server->solid == SOLID_BSP || type == MOVE_HITMODEL)
+ {
+ unsigned int modelindex = (unsigned int)touch->fields.server->modelindex;
+ // if the modelindex is 0, it shouldn't be SOLID_BSP!
+ if (modelindex > 0 && modelindex < MAX_MODELS)
+ model = sv.models[(int)touch->fields.server->modelindex];
+ }
+ if (model)
+ Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+ else
+ Matrix4x4_CreateTranslate(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]);
+ Matrix4x4_Invert_Simple(&imatrix, &matrix);
+ if ((int)touch->fields.server->flags & FL_MONSTER)
+ Collision_ClipToGenericEntity(&trace, model, touch->fields.server->frame, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+ else
+ Collision_ClipToGenericEntity(&trace, model, touch->fields.server->frame, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+
+ Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP);
+ }
+
+ return cliptrace;
+}
+
+#if COLLISIONPARANOID >= 1
+trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
+{
+ int endstuck;
+ trace_t trace;
+ vec3_t temp;
+ trace = SV_Move_(start, mins, maxs, end, type, passedict, hitsupercontentsmask);
+ if (passedict)
+ {
+ VectorCopy(trace.endpos, temp);
+ endstuck = SV_Move_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask).startsolid;
+#if COLLISIONPARANOID < 3
+ if (trace.startsolid || endstuck)
+#endif
+ 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, passedict->fields.server->origin[0], passedict->fields.server->origin[1], passedict->fields.server->origin[2], end[0] - passedict->fields.server->origin[0], end[1] - passedict->fields.server->origin[1], end[2] - passedict->fields.server->origin[2], trace.fraction, trace.endpos[0] - passedict->fields.server->origin[0], trace.endpos[1] - passedict->fields.server->origin[1], trace.endpos[2] - passedict->fields.server->origin[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : "");
+ }
+ return trace;