public static void CL_RelinkEntities() { // determine partial update time float frac = CL_LerpPoint(); cl_numvisedicts = 0; // // interpolate player info // cl.velocity = cl.mvelocity[1] + frac * (cl.mvelocity[0] - cl.mvelocity[1]); if (cls.demoplayback) { // interpolate the angles Vector3 angleDelta = cl.mviewangles[0] - cl.mviewangles[1]; Mathlib.CorrectAngles180(ref angleDelta); cl.viewangles = cl.mviewangles[1] + frac * angleDelta; } float bobjrotate = Mathlib.anglemod(100 * cl.time); // start on the entity after the world for (int i = 1; i < cl.num_entities; i++) { entity_t ent = cl_entities[i]; if (ent.model == null) { // empty slot if (ent.forcelink) { R_RemoveEfrags(ent); // just became empty } continue; } // if the object wasn't included in the last packet, remove it if (ent.msgtime != cl.mtime[0]) { ent.model = null; continue; } Vector3 oldorg = ent.origin; if (ent.forcelink) { // the entity was not updated in the last message // so move to the final spot ent.origin = ent.msg_origins[0]; ent.angles = ent.msg_angles[0]; } else { // if the delta is large, assume a teleport and don't lerp float f = frac; Vector3 delta = ent.msg_origins[0] - ent.msg_origins[1]; if (Math.Abs(delta.X) > 100 || Math.Abs(delta.Y) > 100 || Math.Abs(delta.Z) > 100) { f = 1; // assume a teleportation, not a motion } // interpolate the origin and angles ent.origin = ent.msg_origins[1] + f * delta; Vector3 angleDelta = ent.msg_angles[0] - ent.msg_angles[1]; Mathlib.CorrectAngles180(ref angleDelta); ent.angles = ent.msg_angles[1] + f * angleDelta; } // rotate binary objects locally if ((ent.model.flags & q_shared.EF_ROTATE) != 0) { ent.angles.Y = bobjrotate; } if ((ent.effects & q_shared.EF_BRIGHTFIELD) != 0) { R_EntityParticles(ent); } if ((ent.effects & q_shared.EF_MUZZLEFLASH) != 0) { dlight_t dl = CL_AllocDlight(i); dl.origin = ent.origin; dl.origin.Z += 16; Vector3 fv, rv, uv; Mathlib.AngleVectors(ref ent.angles, out fv, out rv, out uv); dl.origin += fv * 18; dl.radius = 200 + (Random() & 31); dl.minlight = 32; dl.die = (float)cl.time + 0.1f; } if ((ent.effects & q_shared.EF_BRIGHTLIGHT) != 0) { dlight_t dl = CL_AllocDlight(i); dl.origin = ent.origin; dl.origin.Z += 16; dl.radius = 400 + (Random() & 31); dl.die = (float)cl.time + 0.001f; } if ((ent.effects & q_shared.EF_DIMLIGHT) != 0) { dlight_t dl = CL_AllocDlight(i); dl.origin = ent.origin; dl.radius = 200 + (Random() & 31); dl.die = (float)cl.time + 0.001f; } if ((ent.model.flags & q_shared.EF_GIB) != 0) { R_RocketTrail(ref oldorg, ref ent.origin, 2); } else if ((ent.model.flags & q_shared.EF_ZOMGIB) != 0) { R_RocketTrail(ref oldorg, ref ent.origin, 4); } else if ((ent.model.flags & q_shared.EF_TRACER) != 0) { R_RocketTrail(ref oldorg, ref ent.origin, 3); } else if ((ent.model.flags & q_shared.EF_TRACER2) != 0) { R_RocketTrail(ref oldorg, ref ent.origin, 5); } else if ((ent.model.flags & q_shared.EF_ROCKET) != 0) { R_RocketTrail(ref oldorg, ref ent.origin, 0); dlight_t dl = CL_AllocDlight(i); dl.origin = ent.origin; dl.radius = 200; dl.die = (float)cl.time + 0.01f; } else if ((ent.model.flags & q_shared.EF_GRENADE) != 0) { R_RocketTrail(ref oldorg, ref ent.origin, 1); } else if ((ent.model.flags & q_shared.EF_TRACER3) != 0) { R_RocketTrail(ref oldorg, ref ent.origin, 6); } ent.forcelink = false; if (i == cl.viewentity && chase_active.value == 0) { continue; } if (cl_numvisedicts < q_shared.MAX_VISEDICTS) { cl_visedicts[cl_numvisedicts] = ent; cl_numvisedicts++; } } }