//for moving and rotating entities :x private static void CM_TransformedBoxTrace(ref TraceT trace, Vector3 start, Vector3 end, Vector3 mins, Vector3 maxs, BSPNode headnode, BrushContents brushmask, Vector3 origin, Vector3 angles) { Vector3 start_l; Vector3 end_l; bool rotated; Vector3[] axes = new Vector3[3]; start_l = start - origin; end_l = end - origin; rotated = angles != null; if (rotated) { Utils.AnglesToAxis(angles, out axes[0], out axes[1], out axes[2]); start_l = Utils.RotatePoint(start_l, axes); end_l = Utils.RotatePoint(end_l, axes); } CM_BoxTrace(out trace, start_l, end_l, mins, maxs, headnode, (int)brushmask); if (rotated && trace.fraction != 1 && trace.plane != null) { Utils.TransposeAxis(ref axes); trace.plane.normal = Utils.RotatePoint(trace.plane.normal, axes); } //Carmack: FIXME: offset plane distance? M: wut? trace.endpos = Vector3.Lerp(start, end, trace.fraction); }
private static void CL_ClipMoveToEntities(Vector3 start, Vector3 mins, Vector3 maxs, Vector3 end, ref TraceT tr) { TraceT trace = new TraceT(); BSPNode headnode; //entity blah BSPModel cmodel; //null check for physicsModels? if (BSPFile.physicsModels == null) { return; //i guess so } for (int i = 0; i < BSPFile.physicsModels.Count; i++) { cmodel = BSPFile.physicsModels[i].Bmodel; headnode = cmodel.headnode; if (tr.allsolid) { return; } CM_TransformedBoxTrace(ref trace, start, end, mins, maxs, headnode, BrushContents.MASK_PLAYERSOLID, BSPFile.physicsModels[i].Ent.MoveOrigin / Globals.scale.Value, BSPFile.physicsModels[i].Ent.MoveAngles); CM_ClipEntity(ref tr, ref trace, cmodel); } }
private static void CM_TestBoxInBrush(Vector3 p1, ref TraceT trace, BSPBrush brush) { BSPBrushSide[] sides = brush.Sides; BSPPlane plane; float dist, d1; for (int i = 0; i < sides.Length; i++) { plane = sides[i].Plane; dist = Vector3.Dot(trace_offsets[plane.Signbits], plane.normal); dist = plane.distance - dist; d1 = Vector3.Dot(p1, plane.normal) - dist; //completely in front of a face, no intersection if (d1 > 0) { return; } } trace.startsolid = trace.allsolid = true; trace.fraction = 0; trace.contents = brush.contents; }
private static void CM_ClipEntity(ref TraceT dst, ref TraceT src, BSPModel model) { dst.allsolid = src.allsolid; dst.startsolid = src.startsolid; if (src.fraction < dst.fraction) { dst.fraction = src.fraction; dst.endpos = src.endpos; dst.plane = src.plane; dst.surface = src.surface; dst.contents |= src.contents; dst.clipmodel = model; } }
//only radius damage is needed private void Hit(TraceT trace) { //Console.DebugLog("Projectile hit at " + trace.endpos); Vector3 projectilePos = transform.position / scale; Vector3 playerPos = PlayerState.currentOrigin; if ((projectilePos - playerPos).magnitude > damageRadius) { Explode(); return; } Vector3 v = PlayerState.mins + PlayerState.maxs; v = playerPos + v * 0.5f; v = projectilePos - v; //Console.DebugLog("V is " + v.magnitude); #if DEBUG float dmg = radiusDamage; if (Cvar.Exists("debug_rocketmult")) { dmg *= Cvar.Value("debug_rocketmult"); } float knockback = dmg - 0.5f * v.magnitude; #else float knockback = radiusDamage - 0.5f * v.magnitude; #endif knockback *= 0.5f; if (knockback > 0) { Vector3 knockDir = playerPos - projectilePos; float mass = 200; Vector3 velocity = knockDir.normalized * (1600 * knockback / mass); //Console.DebugLog("Knockback force " + velocity.magnitude); PlayerState.addVelocities += velocity; } Explode(); }
/// <summary> /// Sets player extents and viewheight. /// </summary> private static void PM_CheckDuck() { mins.x = -16; mins.z = -16; maxs.x = 16; maxs.z = 16; mins.y = -24; if (InputContainer.upMove < 0 && pmflags.HasFlag(PMFlags.PMF_ON_GROUND)) { pmflags |= PMFlags.PMF_DUCKED; pmd.beginCameraLerp = true; } else { //stand up if possible if (pmflags.HasFlag(PMFlags.PMF_DUCKED)) { //try to stand up maxs.y = 32; TraceT trace = Trace.CL_Trace(origin, mins, maxs, origin); if (!trace.allsolid) { pmflags &= ~PMFlags.PMF_DUCKED; } } } if (pmflags.HasFlag(PMFlags.PMF_DUCKED)) { maxs.y = 4; viewheight = -2; } else { maxs.y = 32; viewheight = 22; } }
private void Fire_c(string[] args) { if (!Cvar.Boolean("console_open")) { if (args.Length > 0) { return; } Weapon w = weaponSlots[currentWeapon]; if (!w) { return; } if (!w.IsCooldown) { float scale = Globals.scale.Value; Projectile p = Instantiate(w.WeaponTemplate.ProjectileModel); p.transform.position = w.transform.position + w.transform.forward * 0.2f; Vector3 far = (playerCamera.transform.position / scale) + playerCamera.transform.forward * 10000; TraceT farTrace = Trace.CL_Trace(playerCamera.transform.position / scale, Vector3.zero, Vector3.zero, far); if (farTrace.fraction < 1) { p.transform.LookAt(farTrace.endpos * scale); //this will always happen if map is sealed and the player is inside the map volume } else { p.transform.forward = w.transform.forward; } p.speed = w.WeaponTemplate.speed; p.damage = w.WeaponTemplate.damage; p.radiusDamage = w.WeaponTemplate.radiusDamage; p.damageRadius = w.WeaponTemplate.damageRadius; w.SetCooldown(w.WeaponTemplate.cooldown); } } }
private void Update() { if (exploding) { return; } aliveTime += Time.unscaledDeltaTime; //stop exisiting at 8 secs... //TODO: add an explosion? if (aliveTime > 8) { Explode(); return; } Vector3 start = transform.position / scale; Vector3 end = start + transform.forward * speed * Time.unscaledDeltaTime; TraceT trace = Trace.CL_Trace(start, Vector3.zero, Vector3.zero, end); if (trace.allsolid) { Hit(trace); return; //shouldnt happen, add destroy here? } //move up to trace end transform.position = trace.endpos * scale; if (trace.fraction < 1) { Hit(trace); } }
private static void CM_BoxTrace(out TraceT trace, Vector3 start, Vector3 end, Vector3 mins, Vector3 maxs, BSPNode headnode, int brushmask) { checkcount++; trace_trace = new TraceT { fraction = 1, surface = new SurfaceT() }; trace = trace_trace; trace_start = start; trace_end = end; trace_contents = brushmask; Vector3[] bounds = new Vector3[] { mins, maxs }; for (int k = 0; k < 8; k++) { trace_offsets[k] = new Vector3(); } for (int i = 0; i < 8; i++) { for (int j = 0; j < 3; j++) { trace_offsets[i][j] = bounds[i >> j & 1][j]; } } //check for position test special case if (start == end) { BSPLeaf[] leafs = new BSPLeaf[1024]; int numleafs; Vector3 c1, c2; //M increase bounds size c1 = start + mins - Vector3.one; c2 = start + maxs + Vector3.one; numleafs = CM_BoxLeafs_Headnode(c1, c2, ref leafs, 1024, headnode, out BSPNode topnode); for (int i = 0; i < numleafs; i++) { CM_TestInLeaf(leaf_list[i]); if (trace_trace.allsolid) { break; } } trace_trace.endpos = start; return; } //check for point special case if (mins == Vector3.zero && maxs == Vector3.zero) { trace_ispoint = true; trace_extents = Vector3.zero; } else { trace_ispoint = false; trace_extents = new Vector3(Mathf.Max(-mins[0], maxs[0]), Mathf.Max(-mins[1], maxs[1]), Mathf.Max(-mins[2], maxs[2])); } //general sweeping through world CM_RecursiveHullCheck(headnode, 0, 1, start, end); if (trace_trace.fraction == 1) { trace_trace.endpos = end; } else { trace_trace.endpos = Vector3.Lerp(start, end, trace_trace.fraction); } }
/// <summary> /// Checks for intersection with a brush during a moving trace. /// </summary> /// <param name="p1">Trace start.</param> /// <param name="p2">Trace end.</param> /// <param name="trace">Data struct.</param> /// <param name="brush">Brush to test against.</param> private static void CM_ClipBoxToBrush(Vector3 p1, Vector3 p2, ref TraceT trace, BSPBrush brush) { int i; BSPPlane plane; BSPPlane clipplane = new BSPPlane(); //initialize this to keep c# happy... float dist; float enterfrac, leavefrac; float d1, d2; bool getout, startout; bool hasclip = false; bool haslead = false; float f; BSPBrushSide leadside = new BSPBrushSide(); //initialize this to keep c# happy... BSPBrushSide[] sides; if (brush.numsides == 0) { return; } sides = brush.Sides; enterfrac = -1; leavefrac = 1; getout = false; //gets out of the brush startout = false; //starts inside the brush for (i = 0; i < brush.numsides; i++) { plane = sides[i].Plane; //we only need plane for each side //get plane to bounds point distance if (!trace_ispoint) { //bounding box trace dist = Vector3.Dot(trace_offsets[plane.Signbits], plane.normal); dist = plane.distance - dist; } else { //point trace dist = plane.distance; } //get distances for start and end of the trace d1 = Vector3.Dot(p1, plane.normal) - dist; //start d2 = Vector3.Dot(p2, plane.normal) - dist; //end if (d2 > 0) { getout = true; //endpoint is not in solid } if (d1 > 0) { startout = true; //starts outside } //if completely in front of a face, no intersection if (d1 > 0 && d2 >= d1) { return; //a single face plane that is not crossed while tracing means that we never hit that brush } //? if (d1 <= 0 && d2 <= 0) { continue; } //crosses face if (d1 > d2) { //enter f = (d1 - DIST_EPSILON) / (d1 - d2); //fraction of the distance covered before hitting a side if (f > enterfrac) { enterfrac = f; clipplane = plane; hasclip = true; //plane clips the trace leadside = sides[i]; haslead = true; //could be combined with hasclip? writes flags for the collided face } } else { //leave f = (d1 + DIST_EPSILON) / (d1 - d2); if (f < leavefrac) { leavefrac = f; } } } //startout wasn't true for any face if (!startout) { //original point was inside brush trace.startsolid = true; if (!getout) { trace.allsolid = true; //map_allsolid_bug trace.fraction = 0; trace.contents = brush.contents; } return; } //after testing all faces we need to see which test went further if (enterfrac < leavefrac) { //only write the test if the brush was closer than any brushes hit before if (enterfrac > -1 && enterfrac < trace.fraction) { if (enterfrac < 0) { enterfrac = 0; } trace.fraction = enterfrac; if (hasclip) { trace.plane = clipplane; } if (haslead) { if (leadside.HasTexInfo) { trace.surface = leadside.TexInfo.Surface; } } trace.contents = brush.contents; } } }