public void ThrustToVelocity(Vector3D velocity) { if (thrustPidController == null) { throw new Exception("wat de neuk thrustPid is null"); } if (thrustControl == null) { throw new Exception("wat de neuk thrustControl is null"); } if (ingameTime == null) { throw new Exception("wat de neuk ingameTime is null"); } Vector3D difference = velocity - ControlVelocity; double differenceMag = difference.Normalize(); double percent = thrustPidController.NextValue(differenceMag, (lastTime - ingameTime.Time).TotalSeconds); percent = MathHelperD.Clamp(percent, 0, 1); thrustControl.ApplyForce(difference, percent); lastTime = ingameTime.Time; }
/// <summary> /// Calculates the output value of a PID loop, given an error and a time step. /// </summary> /// <param name="error">The difference between the Desired and Actual measurement.</param> /// <param name="timeStep">How long it's been since this method has been called (in seconds).</param> /// <returns>The value needed to correct the difference in measurement.</returns> public double CorrectError(double error, double timeStep) { // Derivative term double dInput = error - _lastError; double errorDerivative = _firstRun ? 0 : dInput / timeStep; // Integral term if (!_useIntegralDecay) { _errorIntegral += error * timeStep; _errorIntegral = MathHelperD.Clamp(_errorIntegral, _minOutput, _maxOutput); } else { _errorIntegral = (_errorIntegral * _integralDecay) + (error * timeStep); } // Compute the output double output = _Kp * error + _Ki * _errorIntegral + _Kd * errorDerivative; // Save the error for the next use _lastError = error; _firstRun = false; return(output); }
/// <summary> /// PRONAV /// </summary> /// <param name="target"></param> /// <returns>Heading we need to aim at</returns> public Vector3D Navigate(HaE_Entity target) { Vector3D targetpos = target.entityInfo.Position; if (target.entityInfo.HitPosition.HasValue) { targetpos = target.entityInfo.HitPosition.Value; } Vector3D myVel = controller.control.GetShipVelocities().LinearVelocity; Vector3D rangeVec = targetpos - controller.control.GetPosition(); Vector3D closingVel = target.entityInfo.Velocity - myVel; Vector3D accel = CalculateAccel(rangeVec, closingVel); accel += -controller.control.GetNaturalGravity(); //Gravity term double maxForwardAccel = ThrustUtils.GetForwardThrust(controller.thrusters, controller.control); maxForwardAccel /= controller.control.CalculateShipMass().PhysicalMass; double forwardAccel = maxForwardAccel; double accelMag = accel.Normalize(); forwardAccel -= accelMag; forwardAccel = MathHelperD.Clamp(forwardAccel, 0, maxForwardAccel); accel *= accelMag; accel += Vector3D.Normalize(rangeVec) * forwardAccel; return(accel); }
public bool Update() { //time = distance / rate double rate = MathHelperD.Clamp(lastValue - shipData[Data.Hydrogen].Value, 0, double.MaxValue) / (p.Time - lastTime).TotalSeconds; //rate = amount / time double distance = shipData[Data.Hydrogen].Value; double time = distance / rate; values[index] = time; index++; if (index >= VALUES) { index = 0; } val = values.Average(); lastValue = shipData[Data.Hydrogen].Value; lastTime = p.Time; if (double.IsNaN(val)) { val = 0; } if (val != Value) { Value = val; return(true); } return(false); }
/* * /// Whip's Get Rotation Angles Method v14 - 9/25/18 /// * Dependencies: AngleBetween */ internal static double AngleBetween(Vector3D a, Vector3D b) //returns radians { if (Vector3D.IsZero(a) || Vector3D.IsZero(b)) { return(0); } return(Math.Acos(MathHelperD.Clamp(a.Dot(b) / Math.Sqrt(a.LengthSquared() * b.LengthSquared()), -1, 1))); }
public double Update(double error, TimeSpan sincelastupdate) { double dt = sincelastupdate.TotalSeconds; diff_error = (error - last_error) / dt; accum_error += error * dt; last_error = error; double value = P * error + I * accum_error + D * diff_error; return(MathHelperD.Clamp(value, Min, Max)); }
public static double GetAngleBetween(Vector3D a, Vector3D b) { if (Vector3D.IsZero(a) || Vector3D.IsZero(b)) { return(0); } if (Vector3D.IsUnit(ref a) && Vector3D.IsUnit(ref b)) { return(Math.Acos(MathHelperD.Clamp(a.Dot(b), -1, 1))); } return(Math.Acos(MathHelperD.Clamp(a.Dot(b) / Math.Sqrt(a.LengthSquared() * b.LengthSquared()), -1, 1))); }
public void ThrustToVelocity(Vector3D velocity) { Vector3D difference = velocity - ControlVelocity; double differenceMag = difference.Normalize(); double percent = thrustPidController.NextValue(differenceMag, (lastTime - ingameTime.Time).TotalSeconds); percent = MathHelperD.Clamp(percent, 0, 1); thrustControl.ApplyForce(difference, percent); lastTime = ingameTime.Time; }
public void Apply(float pitch, float yaw, float roll, float dT, bool killRot = false, Vector3D?error = null) { var inputVec = new Vector3D(-pitch, yaw, roll) * dT; var rotationVec = new Vector3D(); inputVec.X += reference.RotationIndicator.X * dT * 100; inputVec.Y += reference.RotationIndicator.Y * dT * 100; inputVec.Z += reference.RollIndicator * dT * 100; rotationVec += inputVec; if (killRot) { KillRotError += AngularVelocity * 200 * dT; if (KillRotError.Length() < .1) { KillRotError *= 0; } rotationVec += new Vector3D( MathHelperD.Clamp(KillRotError.X, -100, 100), MathHelperD.Clamp(KillRotError.Y, -100, 100), MathHelperD.Clamp(KillRotError.Z, -100, 100)); KillRotError += inputVec; KillRotError *= 0.7f; } if (error.HasValue) { gravController.currentError.X = error.Value.X - pitch; gravController.currentError.Y = error.Value.Y - yaw; gravController.currentError.Z = error.Value.Z + roll; gravController.Step(dT); rotationVec += gravController.output; } bool applyOverride = inputVec.Length() > 0 || killRot && KillRotError.Length() != 0; rotationVec *= MathHelper.RadiansPerSecondToRPM; rotationVec.X = MathHelper.Clamp(rotationVec.X, -300, 300); rotationVec.Y = MathHelper.Clamp(rotationVec.Y, -300, 300); rotationVec.Z = MathHelper.Clamp(rotationVec.Z, -300, 300); foreach (var tuple in gyrosToControl) { var gyro = tuple.Value; if (applyOverride) { var rotation = Vector3.TransformNormal(rotationVec, tuple.Key); gyro.Pitch = rotation.X; gyro.Yaw = rotation.Y; gyro.Roll = rotation.Z; } gyro.GyroOverride = applyOverride; } }
internal void DrawLineOffsetEffect(Vector3D pos, Vector3D direction, double tracerLength, float beamRadius, Vector4 color) { MatrixD matrix; var up = MatrixD.Identity.Up; var startPos = pos + -(direction * tracerLength); MatrixD.CreateWorld(ref startPos, ref direction, ref up, out matrix); var offsetMaterial = AmmoDef.Const.TracerMaterial; var tracerLengthSqr = tracerLength * tracerLength; var maxOffset = AmmoDef.AmmoGraphics.Lines.OffsetEffect.MaxOffset; var minLength = AmmoDef.AmmoGraphics.Lines.OffsetEffect.MinLength; var maxLength = MathHelperD.Clamp(AmmoDef.AmmoGraphics.Lines.OffsetEffect.MaxLength, 0, tracerLength); double currentForwardDistance = 0; while (currentForwardDistance < tracerLength) { currentForwardDistance += MyUtils.GetRandomDouble(minLength, maxLength); var lateralXDistance = MyUtils.GetRandomDouble(maxOffset * -1, maxOffset); var lateralYDistance = MyUtils.GetRandomDouble(maxOffset * -1, maxOffset); Offsets.Add(new Vector3D(lateralXDistance, lateralYDistance, currentForwardDistance * -1)); } for (int i = 0; i < Offsets.Count; i++) { Vector3D fromBeam; Vector3D toBeam; if (i == 0) { fromBeam = matrix.Translation; toBeam = Vector3D.Transform(Offsets[i], matrix); } else { fromBeam = Vector3D.Transform(Offsets[i - 1], matrix); toBeam = Vector3D.Transform(Offsets[i], matrix); } Vector3 dir = (toBeam - fromBeam); var length = dir.Length(); var normDir = dir / length; MyTransparentGeometry.AddLineBillboard(offsetMaterial, color, fromBeam, normDir, length, beamRadius); if (Vector3D.DistanceSquared(matrix.Translation, toBeam) > tracerLengthSqr) { break; } } Offsets.Clear(); }
internal void Init(ProInfo info, double firstStepSize, double maxSpeed) { System = info.System; AmmoDef = info.AmmoDef; Ai = info.Ai; IsShrapnel = info.IsShrapnel; if (ParentId != ulong.MaxValue) { Log.Line($"invalid avshot, parentId:{ParentId}"); } ParentId = info.Id; Model = (info.AmmoDef.Const.PrimeModel || info.AmmoDef.Const.TriggerModel) ? Model = ModelState.Exists : Model = ModelState.None; PrimeEntity = info.PrimeEntity; TriggerEntity = info.TriggerEntity; Origin = info.Origin; Offset = AmmoDef.Const.OffsetEffect; MaxTracerLength = info.TracerLength; MuzzleId = info.MuzzleId; WeaponId = info.WeaponId; MaxSpeed = maxSpeed; MaxStepSize = MaxSpeed * MyEngineConstants.PHYSICS_STEP_SIZE_IN_SECONDS; ShootVelStep = info.ShooterVel * MyEngineConstants.PHYSICS_STEP_SIZE_IN_SECONDS; info.Ai.WeaponBase.TryGetValue(info.Target.FiringCube, out FiringWeapon); MaxTrajectory = info.MaxTrajectory; ShotFade = info.ShotFade; ShrinkInited = false; HitEmitter.CanPlayLoopSounds = false; if (AmmoDef.Const.DrawLine) { Tracer = !AmmoDef.Const.IsBeamWeapon && firstStepSize < MaxTracerLength && !MyUtils.IsZero(firstStepSize - MaxTracerLength, 1E-01F) ? TracerState.Grow : TracerState.Full; } else { Tracer = TracerState.Off; } if (AmmoDef.Const.Trail) { MaxGlowLength = MathHelperD.Clamp(AmmoDef.AmmoGraphics.Lines.Trail.DecayTime * MaxStepSize, 0.1f, MaxTrajectory); Trail = AmmoDef.AmmoGraphics.Lines.Trail.Back ? TrailState.Back : Trail = TrailState.Front; GlowShrinkSize = !AmmoDef.AmmoGraphics.Lines.Trail.UseColorFade ? AmmoDef.Const.TrailWidth / AmmoDef.AmmoGraphics.Lines.Trail.DecayTime : 1f / AmmoDef.AmmoGraphics.Lines.Trail.DecayTime; Back = Trail == TrailState.Back; } else { Trail = TrailState.Off; } TotalLength = MathHelperD.Clamp(MaxTracerLength + MaxGlowLength, 0.1f, MaxTrajectory); }
internal void LineVariableEffects() { var color = AmmoDef.AmmoGraphics.Lines.Tracer.Color; if (AmmoDef.Const.LineColorVariance) { var cv = AmmoDef.AmmoGraphics.Lines.ColorVariance; var randomValue = MyUtils.GetRandomFloat(cv.Start, cv.End); color.X *= randomValue; color.Y *= randomValue; color.Z *= randomValue; } Color = color; var tracerWidth = AmmoDef.AmmoGraphics.Lines.Tracer.Width; var trailWidth = AmmoDef.Const.TrailWidth; if (AmmoDef.Const.LineWidthVariance) { var wv = AmmoDef.AmmoGraphics.Lines.WidthVariance; var randomValue = MyUtils.GetRandomFloat(wv.Start, wv.End); tracerWidth += randomValue; if (AmmoDef.AmmoGraphics.Lines.Trail.UseWidthVariance) { trailWidth += randomValue; } } var target = TracerFront + (-Direction * TotalLength); ClosestPointOnLine = MyUtils.GetClosestPointOnLine(ref TracerFront, ref target, ref Ai.Session.CameraPos); DistanceToLine = (float)Vector3D.Distance(ClosestPointOnLine, Ai.Session.CameraMatrix.Translation); if (AmmoDef.Const.IsBeamWeapon && Vector3D.DistanceSquared(TracerFront, TracerBack) > 640000) { target = TracerFront + (-Direction * (TotalLength - MathHelperD.Clamp(DistanceToLine * 6, DistanceToLine, MaxTrajectory * 0.5))); ClosestPointOnLine = MyUtils.GetClosestPointOnLine(ref TracerFront, ref target, ref Ai.Session.CameraPos); DistanceToLine = (float)Vector3D.Distance(ClosestPointOnLine, Ai.Session.CameraMatrix.Translation); } double scale = 0.1f; ScaleFov = Math.Tan(MyAPIGateway.Session.Camera.FovWithZoom * 0.5); TracerWidth = Math.Max(tracerWidth, scale * ScaleFov * (DistanceToLine / 100)); TrailWidth = Math.Max(trailWidth, scale * ScaleFov * (DistanceToLine / 100)); TrailScaler = ((float)TrailWidth / trailWidth); }
private double CalcAccelToStopAtPos(double deltaPos, double curSpd, double maxAccel, double posAccuracy, double AccelPerDeltaPosFactor) { double accel; double absDeltaPos = Math.Abs(deltaPos); //if (absDeltaPos >= posAccuracy) //{ int signDeltaPos = Math.Sign(deltaPos); if (Math.Sign(curSpd) != signDeltaPos) { //удаляемся или не движемся //accel = maxAccel * signDeltaPos; accel = MathHelperD.Clamp(AccelPerDeltaPosFactor * deltaPos * maxAccel, -maxAccel, maxAccel); ToLog("\nудаляемся", true); } else { //приближаемся, оценим тормозной путь double temp = 0.5 * curSpd * curSpd; double brakingDist = temp / maxAccel; ToLog("\nbrakingDist: " + brakingDist.ToString("#0.000"), true); if (absDeltaPos >= brakingDist) { //еще успеем затормозить, поэтому даем максимальное ускорение //accel = maxAccel * signDeltaPos; accel = MathHelperD.Clamp(AccelPerDeltaPosFactor * deltaPos * maxAccel, -maxAccel, maxAccel); ToLog("\nеще успеем: " + absDeltaPos.ToString("#0.00000") + " / " + brakingDist.ToString("#0.00000"), true); } else { //уменьшаем ускорение accel = -temp / deltaPos; ToLog("\nуменьш: " + accel.ToString("#0.000"), true); } } //} //else //{ // accel = AccelPerDeltaPosFactor * deltaPos * maxAccel; // ToLog("\n!!!",true); //} return(accel); }
// check value, set random value if allowed and value not set protected float CheckValue(float value, bool randomize, float minValue, float maxValue, TimeSpan duration, string description) { // overcast if (value < 0 && randomize) { value = (random.Next((int)maxValue * 100) / 100); // ensure there is a value if range is 0 - 1 } else { float correctedValue = (float)MathHelperD.Clamp(value, minValue, maxValue); if (correctedValue != value) { Trace.TraceInformation("Invalid value for {0} for weather at {1} : {2}; value must be between {3} and {4}, clamped to {5}", description, duration.ToString(), value, minValue, maxValue, correctedValue); value = correctedValue; } } return(value); }
internal void PrepOffsetEffect(Vector3D tracerStart, Vector3D direction, double tracerLength) { var up = MatrixD.Identity.Up; var startPos = tracerStart + -(direction * tracerLength); MatrixD.CreateWorld(ref startPos, ref direction, ref up, out OffsetMatrix); TracerLengthSqr = tracerLength * tracerLength; var maxOffset = AmmoDef.AmmoGraphics.Lines.OffsetEffect.MaxOffset; var minLength = AmmoDef.AmmoGraphics.Lines.OffsetEffect.MinLength; var maxLength = MathHelperD.Clamp(AmmoDef.AmmoGraphics.Lines.OffsetEffect.MaxLength, 0, tracerLength); double currentForwardDistance = 0; while (currentForwardDistance <= tracerLength) { currentForwardDistance += MyUtils.GetRandomDouble(minLength, maxLength); var lateralXDistance = MyUtils.GetRandomDouble(maxOffset * -1, maxOffset); var lateralYDistance = MyUtils.GetRandomDouble(maxOffset * -1, maxOffset); Offsets.Add(new Vector3D(lateralXDistance, lateralYDistance, currentForwardDistance * -1)); } }
private static double SignalDamper(double signal, double maxSignal, double value, double maxValue, double beginDamperWorkFactor) { double resault = signal; double beginDamperWork = beginDamperWorkFactor * maxValue; double absValue = Math.Abs(value); if (absValue > beginDamperWork && Math.Sign(signal) == Math.Sign(value)) { double damperWidth = maxValue - beginDamperWork; double damperFactor = MathHelperD.Clamp((maxValue - absValue) / damperWidth, -1.0, 1.0); if (damperFactor >= 0.0) { resault = signal * damperFactor; } else { resault = maxSignal * damperFactor; } } return(resault); }
private Vector3D HPN() { double lambda = LOSRate; double gamma = (PGAIN * LOSRate); float cos = MyMath.FastCos((float)gamma - (float)lambda); double IPNGain = (RelativeVelocityVec.Length() * PGAIN) / (MissileVelocityVec.Length() * cos); IPNGain = MathHelperD.Clamp(IPNGain, MINN, MAXN); IPNGain = (!double.IsNaN(IPNGain)) ? IPNGain : PGAIN; DebugEcho($"IPNGain: {IPNGain:#.###}"); Vector3D accelerationNormal; accelerationNormal = IPNGain * RelativeVelocityVec.Cross(CalculateRotVec()); //PPN term accelerationNormal += IPNGain * TargetAccel / 2; //APN term accelerationNormal += IPNGain * LosDelta; //HPN term accelerationNormal += -rc.GetNaturalGravity(); //Gravity term accelerationNormal += NewLos; //LosBias term return(accelerationNormal); }
private void DamageVoxel(HitEntity hitEnt, ProInfo info) { var entity = hitEnt.Entity; var destObj = hitEnt.Entity as MyVoxelBase; if (destObj == null || entity == null || !hitEnt.HitPos.HasValue) { return; } var shieldHeal = info.AmmoDef.DamageScales.Shields.Type == ShieldDef.ShieldType.Heal; if (!info.AmmoDef.Const.VoxelDamage || shieldHeal) { info.BaseDamagePool = 0; return; } using (destObj.Pin()) { var detonateOnEnd = info.AmmoDef.Const.AmmoAreaEffect && info.AmmoDef.AreaEffect.Detonation.DetonateOnEnd && info.AmmoDef.AreaEffect.AreaEffect != AreaEffectType.Radiant; info.ObjectsHit++; float damageScale = 1; if (info.AmmoDef.Const.VirtualBeams) { damageScale *= info.WeaponCache.Hits; } var scaledDamage = info.BaseDamagePool * damageScale; var fallOff = info.AmmoDef.Const.FallOffScaling && info.DistanceTraveled > info.AmmoDef.DamageScales.FallOff.Distance; if (fallOff) { var fallOffMultipler = (float)MathHelperD.Clamp(1.0 - ((info.DistanceTraveled - info.AmmoDef.DamageScales.FallOff.Distance) / (info.AmmoDef.Const.MaxTrajectory - info.AmmoDef.DamageScales.FallOff.Distance)), info.AmmoDef.DamageScales.FallOff.MinMultipler, 1); scaledDamage *= fallOffMultipler; } var oRadius = info.AmmoDef.AreaEffect.AreaEffectRadius; var minTestRadius = info.DistanceTraveled - info.PrevDistanceTraveled; var tRadius = oRadius < minTestRadius ? minTestRadius : oRadius; var objHp = (int)MathHelper.Clamp(MathFuncs.VolumeCube(MathFuncs.LargestCubeInSphere(tRadius)), 1, double.MaxValue); var sync = MpActive && IsServer; if (tRadius > 5) { objHp *= 5; } if (scaledDamage < objHp) { var reduceBy = objHp / scaledDamage; oRadius /= reduceBy; if (oRadius < 1) { oRadius = 1; } info.BaseDamagePool = 0; } else { info.BaseDamagePool -= objHp; if (oRadius < minTestRadius) { oRadius = minTestRadius; } } destObj.PerformCutOutSphereFast(hitEnt.HitPos.Value, (float)oRadius, true); if (detonateOnEnd) { var det = info.AmmoDef.AreaEffect.Detonation; var dRadius = det.DetonationRadius; var dObjHp = (int)MathHelper.Clamp(MathFuncs.VolumeCube(MathFuncs.LargestCubeInSphere(dRadius)), 1, double.MaxValue); if (dRadius > 5) { dObjHp *= 5; } dObjHp *= 5; var dDamage = det.DetonationDamage; var reduceBy = dObjHp / dDamage; dRadius /= reduceBy; if (dRadius < 1.5) { dRadius = 1.5f; } if (sync) { destObj.PerformCutOutSphereFast(hitEnt.HitPos.Value, dRadius, true); } } } }
internal void Run() { if (Session.Tick180) { Log.LineShortDate($"(DRAWS) --------------- AvShots:[{AvShots.Count}] OnScreen:[{_onScreens}] Shrinks:[{_shrinks}] Glows:[{_glows}] Models:[{_models}] P:[{Session.Projectiles.ActiveProjetiles.Count}] P-Pool:[{Session.Projectiles.ProjectilePool.Count}] AvPool:[{AvShotPool.Count}] (AvBarrels 1:[{AvBarrels1.Count}] 2:[{AvBarrels2.Count}])", "stats"); _glows = 0; _shrinks = 0; } _onScreens = 0; _models = 0; for (int i = AvShots.Count - 1; i >= 0; i--) { var av = AvShots[i]; if (av.OnScreen != AvShot.Screen.None) { _onScreens++; } var refreshed = av.LastTick == Session.Tick; if (refreshed && av.Tracer != AvShot.TracerState.Off && av.OnScreen != AvShot.Screen.None) { var color = av.Color; var segColor = av.SegmentColor; if (av.ShotFade > 0) { var fade = MathHelper.Clamp(1f - av.ShotFade, 0.005f, 1f); color *= fade; segColor *= fade; } if (!av.AmmoDef.Const.OffsetEffect) { if (av.Tracer != AvShot.TracerState.Shrink) { if (av.AmmoDef.Const.TracerMode == AmmoConstants.Texture.Normal) { MyTransparentGeometry.AddLineBillboard(av.AmmoDef.Const.TracerTextures[0], color, av.TracerBack, av.PointDir, (float)av.VisualLength, (float)av.TracerWidth); } else if (av.AmmoDef.Const.TracerMode != AmmoConstants.Texture.Resize) { MyTransparentGeometry.AddLineBillboard(av.AmmoDef.Const.TracerTextures[av.TextureIdx], color, av.TracerBack, av.PointDir, (float)av.VisualLength, (float)av.TracerWidth); } else { var seg = av.AmmoDef.AmmoGraphics.Lines.Tracer.Segmentation; var stepPos = av.TracerBack; var segTextureCnt = av.AmmoDef.Const.SegmentTextures.Length; var gapTextureCnt = av.AmmoDef.Const.TracerTextures.Length; var segStepLen = seg.SegmentLength / segTextureCnt; var gapStepLen = seg.SegmentGap / gapTextureCnt; var gapEnabled = gapStepLen > 0; int j = 0; double travel = 0; while (travel < av.VisualLength) { var mod = j++ % 2; var gap = gapEnabled && (av.SegmentGaped && mod == 0 || !av.SegmentGaped && mod == 1); var first = travel <= 0; double width; double rawLen; Vector4 dyncColor; if (!gap) { rawLen = first ? av.SegmentLenTranserved : seg.SegmentLength; width = av.SegmentWidth; dyncColor = segColor; } else { rawLen = first ? av.SegmentLenTranserved : seg.SegmentGap; width = av.TracerWidth; dyncColor = color; } var notLast = travel + rawLen < av.VisualLength; var len = notLast ? rawLen : av.VisualLength - travel; var clampStep = !gap?MathHelperD.Clamp((int)((len / segStepLen) + 0.5) - 1, 0, segTextureCnt - 1) : MathHelperD.Clamp((int)((len / gapStepLen) + 0.5) - 1, 0, gapTextureCnt); var material = !gap ? av.AmmoDef.Const.SegmentTextures[(int)clampStep] : av.AmmoDef.Const.TracerTextures[(int)clampStep]; MyTransparentGeometry.AddLineBillboard(material, dyncColor, stepPos, av.PointDir, (float)len, (float)width); if (!notLast) { travel = av.VisualLength; } else { travel += len; } stepPos += (av.PointDir * len); } } } } else { var list = av.Offsets; for (int x = 0; x < list.Count; x++) { Vector3D fromBeam; Vector3D toBeam; if (x == 0) { fromBeam = av.OffsetMatrix.Translation; toBeam = Vector3D.Transform(list[x], av.OffsetMatrix); } else { fromBeam = Vector3D.Transform(list[x - 1], av.OffsetMatrix); toBeam = Vector3D.Transform(list[x], av.OffsetMatrix); } Vector3 dir = (toBeam - fromBeam); var length = dir.Length(); var normDir = dir / length; MyTransparentGeometry.AddLineBillboard(av.AmmoDef.Const.TracerTextures[0], color, fromBeam, normDir, length, (float)av.TracerWidth); if (Vector3D.DistanceSquared(av.OffsetMatrix.Translation, toBeam) > av.TracerLengthSqr) { break; } } list.Clear(); } } var shrinkCnt = av.TracerShrinks.Count; if (shrinkCnt > _shrinks) { _shrinks = shrinkCnt; } if (shrinkCnt > 0) { RunShrinks(av); } var glowCnt = av.GlowSteps.Count; if (glowCnt > _glows) { _glows = glowCnt; } if (av.Trail != AvShot.TrailState.Off) { var steps = av.AmmoDef.AmmoGraphics.Lines.Trail.DecayTime; var widthScaler = !av.AmmoDef.AmmoGraphics.Lines.Trail.UseColorFade; var remove = false; for (int j = glowCnt - 1; j >= 0; j--) { var glow = av.GlowSteps[j]; if (!refreshed) { glow.Line = new LineD(glow.Line.From + av.ShootVelStep, glow.Line.To + av.ShootVelStep, glow.Line.Length); } if (av.OnScreen != AvShot.Screen.None) { var reduction = (av.GlowShrinkSize * glow.Step); var width = widthScaler ? (av.AmmoDef.Const.TrailWidth - reduction) * av.TrailScaler : av.AmmoDef.Const.TrailWidth * av.TrailScaler; var color = av.AmmoDef.AmmoGraphics.Lines.Trail.Color; if (!widthScaler) { color *= MathHelper.Clamp(1f - reduction, 0.01f, 1f); } MyTransparentGeometry.AddLineBillboard(av.AmmoDef.Const.TrailTextures[0], color, glow.Line.From, glow.Line.Direction, (float)glow.Line.Length, width); } if (++glow.Step >= steps) { glow.Parent = null; glow.Step = 0; remove = true; glowCnt--; Glows.Push(glow); } } if (remove) { av.GlowSteps.Dequeue(); } } if (glowCnt == 0 && shrinkCnt == 0 && av.MarkForClose) { AvShotPool.Return(av); AvShots.RemoveAtFast(i); } } }
/// <summary> /// Sets the animation to a particular frame whilst clamping it to the frame count range. /// </summary> public void SetFrameClamp(double frame) { SetFrame(MathHelperD.Clamp(frame, 0, FrameCount)); }
private void DamageShield(HitEntity hitEnt, ProInfo info) { var shield = hitEnt.Entity as IMyTerminalBlock; if (shield == null || !hitEnt.HitPos.HasValue) { return; } info.ObjectsHit++; var damageScale = 1; var fallOff = info.AmmoDef.Const.FallOffScaling && info.DistanceTraveled > info.AmmoDef.DamageScales.FallOff.Distance; if (info.AmmoDef.Const.VirtualBeams) { damageScale *= info.WeaponCache.Hits; } var damageType = info.AmmoDef.DamageScales.Shields.Type; var energy = damageType == ShieldDef.ShieldType.Energy; var heal = damageType == ShieldDef.ShieldType.Heal; var shieldByPass = info.AmmoDef.DamageScales.Shields.Type == ShieldDef.ShieldType.Bypass; var areaEffect = info.AmmoDef.AreaEffect; var detonateOnEnd = info.AmmoDef.AreaEffect.Detonation.DetonateOnEnd && areaEffect.AreaEffect != AreaEffectType.Disabled && !shieldByPass; var areaDamage = areaEffect.AreaEffect != AreaEffectType.Disabled ? areaEffect.AreaEffectDamage * (areaEffect.AreaEffectRadius * 0.5f) : 0; var scaledDamage = (((info.BaseDamagePool * damageScale) + areaDamage) * info.AmmoDef.Const.ShieldModifier) * info.AmmoDef.Const.ShieldBypassMod; if (fallOff) { var fallOffMultipler = MathHelperD.Clamp(1.0 - ((info.DistanceTraveled - info.AmmoDef.DamageScales.FallOff.Distance) / (info.AmmoDef.Const.MaxTrajectory - info.AmmoDef.DamageScales.FallOff.Distance)), info.AmmoDef.DamageScales.FallOff.MinMultipler, 1); scaledDamage *= fallOffMultipler; } var detonateDamage = detonateOnEnd ? (areaEffect.Detonation.DetonationDamage * (areaEffect.Detonation.DetonationRadius * 0.5f)) * info.AmmoDef.Const.ShieldModifier : 0; var combinedDamage = (float)(scaledDamage + detonateDamage); if (heal) { combinedDamage *= -1; } var hit = SApi.PointAttackShieldExt(shield, hitEnt.HitPos.Value, info.Target.FiringCube.EntityId, combinedDamage, energy, info.AmmoDef.AmmoGraphics.ShieldHitDraw); if (hit.HasValue) { if (heal) { info.BaseDamagePool = 0; return; } var objHp = hit.Value; if (info.EwarActive) { info.BaseHealthPool -= 1; } else if (objHp > 0) { if (!shieldByPass) { info.BaseDamagePool = 0; } else { info.BaseDamagePool *= info.AmmoDef.Const.ShieldBypassMod; } } else { info.BaseDamagePool = (objHp * -1); } if (info.AmmoDef.Mass <= 0) { return; } var speed = info.AmmoDef.Trajectory.DesiredSpeed > 0 ? info.AmmoDef.Trajectory.DesiredSpeed : 1; ApplyProjectileForce((MyEntity)shield.CubeGrid, hitEnt.HitPos.Value, hitEnt.Intersection.Direction, info.AmmoDef.Mass * speed); } }
internal static void DeferedAvStateUpdates(Session s) { for (int x = 0; x < s.Projectiles.DeferedAvDraw.Count; x++) { var d = s.Projectiles.DeferedAvDraw[x]; var i = d.Info; var a = i.AvShot; var lineEffect = a.AmmoDef.Const.Trail || a.AmmoDef.Const.DrawLine; var saveHit = d.Hit; ++a.LifeTime; a.LastTick = s.Tick; a.StepSize = d.StepSize; a.EstTravel = a.StepSize * a.LifeTime; a.ShortStepSize = d.ShortStepSize ?? d.StepSize; a.ShortEstTravel = MathHelperD.Clamp((a.EstTravel - a.StepSize) + a.ShortStepSize, 0, double.MaxValue); a.VisualLength = d.VisualLength; a.TracerFront = d.TracerFront; a.Direction = i.Direction; a.PointDir = !saveHit && !a.Back && a.GlowSteps.Count > 0 ? a.GlowSteps[a.GlowSteps.Count - 1].Line.Direction : i.VisualDir; a.TracerBack = a.TracerFront + (-a.Direction * a.VisualLength); a.OnScreen = Screen.None; // clear OnScreen if (i.ModelOnly) { a.ModelSphereCurrent.Center = a.TracerFront; if (a.Triggered) { a.ModelSphereCurrent.Radius = i.TriggerGrowthSteps < a.AmmoDef.Const.AreaEffectSize ? a.TriggerMatrix.Scale.AbsMax() : a.AmmoDef.Const.AreaEffectSize; } if (s.Camera.IsInFrustum(ref a.ModelSphereCurrent)) { a.OnScreen = Screen.ModelOnly; } } else if (lineEffect || a.Model == ModelState.None && a.AmmoDef.Const.AmmoParticle) { var rayTracer = new RayD(a.TracerBack, a.PointDir); var rayTrail = new RayD(a.TracerFront + (-a.Direction * a.ShortEstTravel), a.Direction); //DsDebugDraw.DrawRay(rayTracer, VRageMath.Color.White, 0.25f, (float) VisualLength); //DsDebugDraw.DrawRay(rayTrail, VRageMath.Color.Orange, 0.25f, (float)ShortEstTravel); double?dist; s.CameraFrustrum.Intersects(ref rayTracer, out dist); if (dist != null && dist <= a.VisualLength) { a.OnScreen = Screen.Tracer; } else if (a.AmmoDef.Const.Trail) { s.CameraFrustrum.Intersects(ref rayTrail, out dist); if (dist != null && dist <= a.ShortEstTravel + a.ShortStepSize) { a.OnScreen = Screen.Trail; } } if (a.OnScreen != Screen.None && !a.TrailActivated && a.AmmoDef.Const.Trail) { a.TrailActivated = true; } if (a.OnScreen == Screen.None && a.TrailActivated) { a.OnScreen = Screen.Trail; } if (a.Model != ModelState.None) { a.ModelSphereCurrent.Center = a.TracerFront; if (a.Triggered) { a.ModelSphereCurrent.Radius = i.TriggerGrowthSteps < a.AmmoDef.Const.AreaEffectSize ? a.TriggerMatrix.Scale.AbsMax() : a.AmmoDef.Const.AreaEffectSize; } if (a.OnScreen == Screen.None && s.Camera.IsInFrustum(ref a.ModelSphereCurrent)) { a.OnScreen = Screen.ModelOnly; } } } if (a.OnScreen == Screen.None && Vector3D.DistanceSquared(a.TracerFront, a.Ai.Session.CameraPos) <= 225) { a.OnScreen = Screen.InProximity; } if (i.MuzzleId == -1) { return; } if (saveHit) { a.HitVelocity = a.Hit.HitVelocity; a.Hitting = !a.ShrinkInited; } a.LastStep = a.Hitting || MyUtils.IsZero(a.MaxTrajectory - a.ShortEstTravel, 1E-01F); if (a.AmmoDef.Const.DrawLine) { if (a.AmmoDef.Const.IsBeamWeapon || !saveHit && MyUtils.IsZero(a.MaxTracerLength - a.VisualLength, 1E-01F)) { a.Tracer = TracerState.Full; } else if (a.Tracer != TracerState.Off && a.VisualLength <= 0) { a.Tracer = TracerState.Off; } else if (a.Hitting && !i.ModelOnly && lineEffect && a.VisualLength / a.StepSize > 1 && !MyUtils.IsZero(a.EstTravel - a.ShortEstTravel, 1E-01F)) { a.Tracer = TracerState.Shrink; a.TotalLength = MathHelperD.Clamp(a.VisualLength + a.MaxGlowLength, 0.1f, Vector3D.Distance(a.Origin, a.TracerFront)); } else if (a.Tracer == TracerState.Grow && a.LastStep) { a.Tracer = TracerState.Full; } } var lineOnScreen = a.OnScreen > (Screen)2; if (lineEffect && (a.Active || lineOnScreen)) { a.LineVariableEffects(); } if (a.Tracer != TracerState.Off && lineOnScreen) { if (a.Tracer == TracerState.Shrink && !a.ShrinkInited) { a.Shrink(); } else if (a.AmmoDef.Const.IsBeamWeapon && a.Hitting && a.AmmoDef.Const.HitParticle && !(a.MuzzleId != 0 && (a.AmmoDef.Const.ConvergeBeams || a.AmmoDef.Const.OneHitParticle))) { ContainmentType containment; s.CameraFrustrum.Contains(ref a.Hit.HitPos, out containment); if (containment != ContainmentType.Disjoint) { a.RunBeam(); } } if (a.AmmoDef.Const.OffsetEffect) { a.PrepOffsetEffect(a.TracerFront, a.PointDir, a.VisualLength); } } var backAndGrowing = a.Back && a.Tracer == TracerState.Grow; if (a.Trail != TrailState.Off && !backAndGrowing && lineOnScreen) { a.RunGlow(ref a.EmptyShrink); } if (!a.Active && a.OnScreen != Screen.None) { a.Active = true; s.Av.AvShots.Add(a); } a.Hitting = false; } s.Projectiles.DeferedAvDraw.Clear(); }
internal static bool WeaponLookAt(Weapon weapon, ref Vector3D targetDir, double targetDistSqr, bool setWeapon, bool canSeeOnly, out bool isTracking) { var system = weapon.System; var target = weapon.Target; isTracking = false; //Get weapon direction and orientation Vector3D currentVector; Vector3D.CreateFromAzimuthAndElevation(weapon.Azimuth, weapon.Elevation, out currentVector); Vector3D.Rotate(ref currentVector, ref weapon.WeaponConstMatrix, out currentVector); var up = weapon.MyPivotUp; Vector3D left; Vector3D.Cross(ref up, ref currentVector, out left); if (!Vector3D.IsUnit(ref left) && !Vector3D.IsZero(left)) { left.Normalize(); } Vector3D forward; Vector3D.Cross(ref left, ref up, out forward); var constraintMatrix = new MatrixD { Forward = forward, Left = left, Up = up, }; // ugly as sin inlined compute GetRotationAngles + AngleBetween, returning the desired az/el doubles; var transposeMatrix = MatrixD.Transpose(constraintMatrix); Vector3D localTargetVector; Vector3D.TransformNormal(ref targetDir, ref transposeMatrix, out localTargetVector); var flattenedTargetVector = new Vector3D(localTargetVector.X, 0, localTargetVector.Z); var azVecIsZero = Vector3D.IsZero(flattenedTargetVector); var flatSqr = flattenedTargetVector.LengthSquared(); var desiredAzimuth = azVecIsZero ? 0 : Math.Acos(MathHelperD.Clamp(-flattenedTargetVector.Z / Math.Sqrt(flatSqr), -1, 1)) * -Math.Sign(localTargetVector.X); //right is positive; if (Math.Abs(desiredAzimuth) < 1E-6 && localTargetVector.Z > 0) //check for straight back case { desiredAzimuth = Math.PI; } double desiredElevation; if (Vector3D.IsZero(flattenedTargetVector)) //check for straight up case { desiredElevation = MathHelper.PiOver2 * Math.Sign(localTargetVector.Y); } else { var elVecIsZero = Vector3D.IsZero(localTargetVector) || Vector3D.IsZero(flattenedTargetVector); desiredElevation = elVecIsZero ? 0 : Math.Acos(MathHelperD.Clamp(localTargetVector.Dot(flattenedTargetVector) / Math.Sqrt(localTargetVector.LengthSquared() * flatSqr), -1, 1)) * Math.Sign(localTargetVector.Y); //up is positive } // return result of desired values being in tolerances if (canSeeOnly) { if (weapon.Azimuth + desiredAzimuth > weapon.MaxAzToleranceRadians && weapon.MaxAzToleranceRadians < Math.PI) { return(false); } if (weapon.Azimuth + desiredAzimuth < weapon.MinAzToleranceRadians && weapon.MinAzToleranceRadians > -Math.PI) { return(false); } if (desiredElevation < weapon.MinElToleranceRadians || desiredElevation > weapon.MaxElToleranceRadians) { return(false); } return(true); } // check for backAround constraint double azToTraverse; if (weapon.MaxAzToleranceRadians < Math.PI && weapon.MinAzToleranceRadians > -Math.PI) { var azAngle = weapon.Azimuth + desiredAzimuth; if (azAngle > Math.PI) { azAngle -= MathHelperD.TwoPi; } else if (azAngle < -Math.PI) { azAngle = MathHelperD.TwoPi + azAngle; } azToTraverse = azAngle - weapon.Azimuth; } else { azToTraverse = desiredAzimuth; } // Clamp step within limits. var azStep = MathHelperD.Clamp(azToTraverse, -system.AzStep, system.AzStep); var elStep = MathHelperD.Clamp(desiredElevation - weapon.Elevation, -system.ElStep, system.ElStep); // epsilon based on target type and distance var epsilon = target.IsProjectile || system.Session.Tick120 ? 1E-06d : targetDistSqr <= 640000 ? 1E-03d : targetDistSqr <= 3240000 ? 1E-04d : 1E-05d; // check if step is within epsilon of zero; var azLocked = MyUtils.IsZero(azStep, (float)epsilon); var elLocked = MyUtils.IsZero(elStep, (float)epsilon); // are az and el both within tolerance of target var locked = azLocked && elLocked; // Compute actual angle to rotate subparts var az = weapon.Azimuth + azStep; var el = weapon.Elevation + elStep; // This is where we should clamp. az and el are measured relative the WorldMatrix.Forward. // desiredAzimuth is measured off of the CURRENT heading of the barrel. The limits are based off of // WorldMatrix.Forward as well. var azHitLimit = false; var elHitLimit = false; // Check azimuth angles if (az > weapon.MaxAzToleranceRadians && weapon.MaxAzToleranceRadians < Math.PI) { // Hit upper azimuth limit az = weapon.MaxAzToleranceRadians; azHitLimit = true; } else if (az < weapon.MinAzToleranceRadians && weapon.MinAzToleranceRadians > -Math.PI) { // Hit lower azimuth limit az = weapon.MinAzToleranceRadians; azHitLimit = true; } // Check elevation angles if (el > weapon.MaxElToleranceRadians) { // Hit upper elevation limit el = weapon.MaxElToleranceRadians; elHitLimit = true; } else if (el < weapon.MinElToleranceRadians) { // Hit lower elevation limit el = weapon.MinElToleranceRadians; elHitLimit = true; } // Weapon has a degree of freedom to move towards target var tracking = !azHitLimit && !elHitLimit; if (setWeapon) { isTracking = tracking; if (!azLocked) { weapon.Azimuth = az; weapon.AzimuthTick = system.Session.Tick; } if (!elLocked) { weapon.Elevation = el; weapon.ElevationTick = system.Session.Tick; } } return(!locked); }
/// <summary> /// SkyDrawer constructor /// </summary> public MSTSSkyDrawer(Viewer viewer) { MSTSSkyViewer = viewer; MSTSSkyMaterial = viewer.MaterialManager.Load("MSTSSky"); // Instantiate classes MSTSSkyMesh = new MSTSSkyMesh(MSTSSkyViewer.RenderProcess); MSTSSkyVectors = new SunMoonPos(); //viewer.World.MSTSSky.MSTSSkyMaterial.Viewer.MaterialManager.sunDirection.Y < 0 // Set default values mstsskyseasonType = (int)MSTSSkyViewer.Simulator.Season; date.ordinalDate = 82 + mstsskyseasonType * 91; // TODO: Set the following three externally from ORTS route files (future) date.month = 1 + date.ordinalDate / 30; date.day = 21; date.year = 2010; // Default wind speed and direction mstsskywindSpeed = 5.0f; // m/s (approx 11 mph) mstsskywindDirection = 4.7f; // radians (approx 270 deg, i.e. westerly) // The following keyboard commands are used for viewing sky and weather effects in "demo" mode. // Control- and Control+ for overcast, Shift- and Shift+ for fog and - and + for time. // Don't let multiplayer clients adjust the weather. if (!MPManager.IsClient()) { // Overcast ranges from 0 (completely clear) to 1 (completely overcast). viewer.UserCommandController.AddEvent(UserCommand.DebugOvercastIncrease, KeyEventType.KeyDown, (GameTime gameTIme) => { mstsskyovercastFactor = (float)MathHelperD.Clamp(mstsskyovercastFactor + gameTIme.ElapsedGameTime.TotalSeconds / 10, 0, 1); }); viewer.UserCommandController.AddEvent(UserCommand.DebugOvercastDecrease, KeyEventType.KeyDown, (GameTime gameTIme) => { mstsskyovercastFactor = (float)MathHelperD.Clamp(mstsskyovercastFactor - gameTIme.ElapsedGameTime.TotalSeconds / 10, 0, 1); }); // Fog ranges from 10m (can't see anything) to 100km (clear arctic conditions). viewer.UserCommandController.AddEvent(UserCommand.DebugFogIncrease, KeyEventType.KeyDown, (GameTime gameTIme) => { mstsskyfogDistance = (float)MathHelperD.Clamp(mstsskyfogDistance - gameTIme.ElapsedGameTime.TotalSeconds * mstsskyfogDistance, 10, 100000); }); viewer.UserCommandController.AddEvent(UserCommand.DebugFogDecrease, KeyEventType.KeyDown, (GameTime gameTIme) => { mstsskyfogDistance = (float)MathHelperD.Clamp(mstsskyfogDistance + gameTIme.ElapsedGameTime.TotalSeconds * mstsskyfogDistance, 10, 100000); }); } // Don't let clock shift if multiplayer. if (!MPManager.IsMultiPlayer()) { // Shift the clock forwards or backwards at 1h-per-second. viewer.UserCommandController.AddEvent(UserCommand.DebugClockForwards, KeyEventType.KeyDown, (GameTime gameTIme) => { MSTSSkyViewer.Simulator.ClockTime += gameTIme.ElapsedGameTime.TotalSeconds * 3600; }); viewer.UserCommandController.AddEvent(UserCommand.DebugClockBackwards, KeyEventType.KeyDown, (GameTime gameTIme) => { MSTSSkyViewer.Simulator.ClockTime -= gameTIme.ElapsedGameTime.TotalSeconds * 3600; }); } // Server needs to notify clients of weather changes. if (MPManager.IsServer()) { viewer.UserCommandController.AddEvent(UserCommand.DebugOvercastIncrease, KeyEventType.KeyReleased, SendMultiPlayerSkyChangeNotification); viewer.UserCommandController.AddEvent(UserCommand.DebugOvercastDecrease, KeyEventType.KeyReleased, SendMultiPlayerSkyChangeNotification); viewer.UserCommandController.AddEvent(UserCommand.DebugFogIncrease, KeyEventType.KeyReleased, SendMultiPlayerSkyChangeNotification); viewer.UserCommandController.AddEvent(UserCommand.DebugFogDecrease, KeyEventType.KeyReleased, SendMultiPlayerSkyChangeNotification); } }
internal static bool TrackingTarget(Weapon weapon, Target target) { Vector3D targetPos; Vector3 targetLinVel = Vector3.Zero; Vector3 targetAccel = Vector3.Zero; var system = weapon.System; Vector3D targetCenter; var rayCheckTest = !weapon.Comp.Session.IsClient && weapon.Comp.State.Value.CurrentPlayerControl.ControlType == ControlType.None && weapon.ActiveAmmoDef.AmmoDef.Trajectory.Guidance == GuidanceType.None && (!weapon.Casting && weapon.Comp.Session.Tick - weapon.Comp.LastRayCastTick > 29 || weapon.System.Values.HardPoint.Other.MuzzleCheck && weapon.Comp.Session.Tick - weapon.LastMuzzleCheck > 29); if (rayCheckTest && !weapon.RayCheckTest()) { return(false); } if (weapon.Comp.TrackReticle) { targetCenter = weapon.Comp.Ai.DummyTarget.Position; } else if (target.IsProjectile) { if (target.Projectile == null) { Log.Line($"TrackingTarget: is projectile and it is null"); targetCenter = Vector3D.Zero; } else { targetCenter = target.Projectile.Position; } } else if (!target.IsFakeTarget) { if (target.Entity == null) { Log.Line($"TrackingTarget: is entity and it is null"); targetCenter = Vector3D.Zero; } else { targetCenter = target.Entity.PositionComp.WorldAABB.Center; } } else { targetCenter = Vector3D.Zero; } var needsPrediction = weapon.System.Prediction != Prediction.Off && (!weapon.ActiveAmmoDef.AmmoDef.Const.IsBeamWeapon && weapon.ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed > 0); if (needsPrediction) { if (weapon.Comp.TrackReticle) { targetLinVel = weapon.Comp.Ai.DummyTarget.LinearVelocity; targetAccel = weapon.Comp.Ai.DummyTarget.Acceleration; } else { var topMostEnt = target.Entity?.GetTopMostParent(); if (target.Projectile != null) { targetLinVel = target.Projectile.Velocity; targetAccel = target.Projectile.AccelVelocity; } else if (topMostEnt?.Physics != null) { targetLinVel = topMostEnt.Physics.LinearVelocity; targetAccel = topMostEnt.Physics.LinearAcceleration; } } if (Vector3D.IsZero(targetLinVel, 5E-03)) { targetLinVel = Vector3.Zero; } if (Vector3D.IsZero(targetAccel, 5E-03)) { targetAccel = Vector3.Zero; } targetPos = weapon.GetPredictedTargetPosition(targetCenter, targetLinVel, targetAccel); } else { targetPos = targetCenter; } weapon.Target.TargetPos = targetPos; double rangeToTargetSqr; Vector3D.DistanceSquared(ref targetPos, ref weapon.MyPivotPos, out rangeToTargetSqr); var targetDir = targetPos - weapon.MyPivotPos; var locked = true; if (weapon.Comp.TrackReticle || rangeToTargetSqr <= weapon.MaxTargetDistanceSqr) { var maxAzimuthStep = system.AzStep; var maxElevationStep = system.ElStep; Vector3D currentVector; Vector3D.CreateFromAzimuthAndElevation(weapon.Azimuth, weapon.Elevation, out currentVector); currentVector = Vector3D.Rotate(currentVector, weapon.WeaponConstMatrix); var up = weapon.MyPivotUp; var left = Vector3D.Cross(up, currentVector); if (!Vector3D.IsUnit(ref left) && !Vector3D.IsZero(left)) { left.Normalize(); } var forward = Vector3D.Cross(left, up); var constraintMatrix = new MatrixD { Forward = forward, Left = left, Up = up, }; double desiredAzimuth; double desiredElevation; MathFuncs.GetRotationAngles(ref targetDir, ref constraintMatrix, out desiredAzimuth, out desiredElevation); var azConstraint = Math.Min(weapon.MaxAzimuthRadians, Math.Max(weapon.MinAzimuthRadians, desiredAzimuth)); var elConstraint = Math.Min(weapon.MaxElevationRadians, Math.Max(weapon.MinElevationRadians, desiredElevation)); var elConstrained = Math.Abs(elConstraint - desiredElevation) > 0.0000001; var azConstrained = Math.Abs(azConstraint - desiredAzimuth) > 0.0000001; weapon.Target.IsTracking = !azConstrained && !elConstrained; if (weapon.Target.IsTracking && weapon.Comp.State.Value.CurrentPlayerControl.ControlType != ControlType.Camera && !weapon.Comp.ResettingSubparts) { var oldAz = weapon.Azimuth; var oldEl = weapon.Elevation; var epsilon = target.IsProjectile ? 1E-06d : rangeToTargetSqr <= 640000 ? 1E-03d : rangeToTargetSqr <= 3240000 ? 1E-04d : 1E-05d; var az = weapon.Azimuth + MathHelperD.Clamp(desiredAzimuth, -maxAzimuthStep, maxAzimuthStep); var el = weapon.Elevation + MathHelperD.Clamp(desiredElevation - weapon.Elevation, -maxElevationStep, maxElevationStep); var azDiff = oldAz - az; var elDiff = oldEl - el; var azLocked = MyUtils.IsZero(azDiff, (float)epsilon); var elLocked = MyUtils.IsZero(elDiff, (float)epsilon); locked = azLocked && elLocked; var aim = !azLocked || !elLocked; if (aim) { if (!azLocked) { weapon.Azimuth = az; } if (!elLocked) { weapon.Elevation = el; } weapon.IsHome = false; weapon.AimBarrel(azDiff, elDiff, !azLocked, !elLocked); } } } else { weapon.Target.IsTracking = false; } if (weapon.Comp.State.Value.CurrentPlayerControl.ControlType == ControlType.Camera) { return(weapon.Target.IsTracking); } var isAligned = false; if (weapon.Target.IsTracking) { isAligned = locked || MathFuncs.IsDotProductWithinTolerance(ref weapon.MyPivotDir, ref targetDir, weapon.AimingTolerance); } var wasAligned = weapon.Target.IsAligned; weapon.Target.IsAligned = isAligned; var alignedChange = wasAligned != isAligned; if (alignedChange && isAligned) { if (weapon.System.DesignatorWeapon) { for (int i = 0; i < weapon.Comp.Platform.Weapons.Length; i++) { var w = weapon.Comp.Platform.Weapons[i]; w.Target.StateChange(false, Target.States.Expired); w.Target.CheckTick -= 240; } } } else if (alignedChange && !weapon.System.DelayCeaseFire) { weapon.StopShooting(); } weapon.Target.TargetLock = weapon.Target.IsTracking && weapon.Target.IsAligned; return(weapon.Target.IsTracking); }
private static void DamageProjectile(HitEntity hitEnt, ProInfo attacker) { var pTarget = hitEnt.Projectile; if (pTarget == null) { return; } attacker.ObjectsHit++; var objHp = pTarget.Info.BaseHealthPool; var integrityCheck = attacker.AmmoDef.DamageScales.MaxIntegrity > 0; if (integrityCheck && objHp > attacker.AmmoDef.DamageScales.MaxIntegrity) { return; } float damageScale = 1; if (attacker.AmmoDef.Const.VirtualBeams) { damageScale *= attacker.WeaponCache.Hits; } var scaledDamage = attacker.BaseDamagePool * damageScale; var fallOff = attacker.AmmoDef.Const.FallOffScaling && attacker.DistanceTraveled > attacker.AmmoDef.DamageScales.FallOff.Distance; if (fallOff) { var fallOffMultipler = (float)MathHelperD.Clamp(1.0 - ((attacker.DistanceTraveled - attacker.AmmoDef.DamageScales.FallOff.Distance) / (attacker.AmmoDef.Const.MaxTrajectory - attacker.AmmoDef.DamageScales.FallOff.Distance)), attacker.AmmoDef.DamageScales.FallOff.MinMultipler, 1); scaledDamage *= fallOffMultipler; } if (scaledDamage >= objHp) { attacker.BaseDamagePool -= objHp; pTarget.Info.BaseHealthPool = 0; pTarget.State = Projectile.ProjectileState.Destroy; } else { attacker.BaseDamagePool = 0; pTarget.Info.BaseHealthPool -= scaledDamage; if (attacker.DetonationDamage > 0 && attacker.AmmoDef.AreaEffect.Detonation.DetonateOnEnd) { var areaSphere = new BoundingSphereD(pTarget.Position, attacker.AmmoDef.AreaEffect.Detonation.DetonationRadius); foreach (var sTarget in attacker.Ai.LiveProjectile) { if (areaSphere.Contains(sTarget.Position) != ContainmentType.Disjoint) { if (attacker.DetonationDamage >= sTarget.Info.BaseHealthPool) { sTarget.Info.BaseHealthPool = 0; sTarget.State = Projectile.ProjectileState.Destroy; } else { sTarget.Info.BaseHealthPool -= attacker.DetonationDamage; } } } } } }
public AmmoConstants(WeaponAmmoTypes ammo, WeaponDefinition wDef, Session session, WeaponSystem system) { MyInventory.GetItemVolumeAndMass(ammo.AmmoDefinitionId, out MagMass, out MagVolume); MagazineDef = MyDefinitionManager.Static.GetAmmoMagazineDefinition(ammo.AmmoDefinitionId); TracerMaterial = MyStringId.GetOrCompute(ammo.AmmoDef.AmmoGraphics.Lines.TracerMaterial); TrailMaterial = MyStringId.GetOrCompute(ammo.AmmoDef.AmmoGraphics.Lines.Trail.Material); if (ammo.AmmoDefinitionId.SubtypeId.String != "Energy" || ammo.AmmoDefinitionId.SubtypeId.String == string.Empty) { AmmoItem = new MyPhysicalInventoryItem() { Amount = 1, Content = MyObjectBuilderSerializer.CreateNewObject <MyObjectBuilder_AmmoMagazine>(ammo.AmmoDefinitionId.SubtypeName) } } ; for (int i = 0; i < wDef.Ammos.Length; i++) { var ammoType = wDef.Ammos[i]; if (ammoType.AmmoRound.Equals(ammo.AmmoDef.Shrapnel.AmmoRound)) { ShrapnelId = i; } } IsMine = ammo.AmmoDef.Trajectory.Guidance == DetectFixed || ammo.AmmoDef.Trajectory.Guidance == DetectSmart || ammo.AmmoDef.Trajectory.Guidance == DetectTravelTo; IsField = ammo.AmmoDef.Trajectory.FieldTime > 0; IsHybrid = ammo.AmmoDef.HybridRound; IsTurretSelectable = !ammo.IsShrapnel || ammo.AmmoDef.HardPointUsable; AmmoParticle = ammo.AmmoDef.AmmoGraphics.Particles.Ammo.Name != string.Empty; AmmoParticleShrinks = ammo.AmmoDef.AmmoGraphics.Particles.Ammo.ShrinkByDistance; HitParticleShrinks = ammo.AmmoDef.AmmoGraphics.Particles.Hit.ShrinkByDistance; HitParticle = ammo.AmmoDef.AmmoGraphics.Particles.Hit.Name != string.Empty; DrawLine = ammo.AmmoDef.AmmoGraphics.Lines.Tracer.Enable; LineColorVariance = ammo.AmmoDef.AmmoGraphics.Lines.ColorVariance.Start > 0 && ammo.AmmoDef.AmmoGraphics.Lines.ColorVariance.End > 0; LineWidthVariance = ammo.AmmoDef.AmmoGraphics.Lines.WidthVariance.Start > 0 || ammo.AmmoDef.AmmoGraphics.Lines.WidthVariance.End > 0; SpeedVariance = ammo.AmmoDef.Trajectory.SpeedVariance.Start > 0 || ammo.AmmoDef.Trajectory.SpeedVariance.End > 0; RangeVariance = ammo.AmmoDef.Trajectory.RangeVariance.Start > 0 || ammo.AmmoDef.Trajectory.RangeVariance.End > 0; TrailWidth = ammo.AmmoDef.AmmoGraphics.Lines.Trail.CustomWidth > 0 ? ammo.AmmoDef.AmmoGraphics.Lines.Trail.CustomWidth : ammo.AmmoDef.AmmoGraphics.Lines.Tracer.Width; TargetOffSet = ammo.AmmoDef.Trajectory.Smarts.Inaccuracy > 0; TargetLossTime = ammo.AmmoDef.Trajectory.TargetLossTime > 0 ? ammo.AmmoDef.Trajectory.TargetLossTime : int.MaxValue; CanZombie = TargetLossTime > 0 && TargetLossTime != int.MaxValue && !IsMine; MaxLifeTime = ammo.AmmoDef.Trajectory.MaxLifeTime > 0 ? ammo.AmmoDef.Trajectory.MaxLifeTime : int.MaxValue; MaxChaseTime = ammo.AmmoDef.Trajectory.Smarts.MaxChaseTime > 0 ? ammo.AmmoDef.Trajectory.Smarts.MaxChaseTime : int.MaxValue; MaxObjectsHit = ammo.AmmoDef.ObjectsHit.MaxObjectsHit > 0 ? ammo.AmmoDef.ObjectsHit.MaxObjectsHit : int.MaxValue; BaseDamage = ammo.AmmoDef.BaseDamage; MaxTargets = ammo.AmmoDef.Trajectory.Smarts.MaxTargets; TargetLossDegree = ammo.AmmoDef.Trajectory.TargetLossDegree > 0 ? (float)Math.Cos(MathHelper.ToRadians(ammo.AmmoDef.Trajectory.TargetLossDegree)) : 0; ShieldModifier = ammo.AmmoDef.DamageScales.Shields.Modifier > 0 ? ammo.AmmoDef.DamageScales.Shields.Modifier : 1; ShieldBypassMod = ammo.AmmoDef.DamageScales.Shields.BypassModifier > 0 && ammo.AmmoDef.DamageScales.Shields.BypassModifier < 1 ? ammo.AmmoDef.DamageScales.Shields.BypassModifier : 1; AmmoSkipAccel = ammo.AmmoDef.Trajectory.AccelPerSec <= 0; FeelsGravity = ammo.AmmoDef.Trajectory.GravityMultiplier > 0; MaxTrajectory = ammo.AmmoDef.Trajectory.MaxTrajectory; MaxTrajectorySqr = MaxTrajectory * MaxTrajectory; HasBackKickForce = ammo.AmmoDef.BackKickForce > 0; MaxLateralThrust = MathHelperD.Clamp(ammo.AmmoDef.Trajectory.Smarts.MaxLateralThrust, 0.000001, 1); Fields(ammo.AmmoDef, out PulseInterval, out PulseChance, out Pulse); AreaEffects(ammo.AmmoDef, out AreaEffect, out AreaEffectDamage, out AreaEffectSize, out DetonationDamage, out AmmoAreaEffect, out AreaRadiusSmall, out AreaRadiusLarge, out DetonateRadiusSmall, out DetonateRadiusLarge, out Ewar, out EwarEffect, out EwarTriggerRange); DamageScales(ammo.AmmoDef, out DamageScaling, out FallOffScaling, out ArmorScaling, out CustomDamageScales, out CustomBlockDefinitionBasesToScales, out SelfDamage, out VoxelDamage); Beams(ammo.AmmoDef, out IsBeamWeapon, out VirtualBeams, out RotateRealBeam, out ConvergeBeams, out OneHitParticle, out OffsetEffect); CollisionShape(ammo.AmmoDef, out CollisionIsLine, out CollisionSize, out TracerLength); SmartsDelayDistSqr = (CollisionSize * ammo.AmmoDef.Trajectory.Smarts.TrackingDelay) * (CollisionSize * ammo.AmmoDef.Trajectory.Smarts.TrackingDelay); PrimeEntityPool = Models(ammo.AmmoDef, wDef, out PrimeModel, out TriggerModel, out ModelPath); Energy(ammo, system, wDef, out EnergyAmmo, out MustCharge, out Reloadable, out EnergyMagSize, out BurstMode, out HasShotReloadDelay); Sound(ammo.AmmoDef, session, out HitSound, out AmmoTravelSound, out HitSoundDistSqr, out AmmoTravelSoundDistSqr, out AmmoSoundMaxDistSqr); MagazineSize = EnergyAmmo ? EnergyMagSize : MagazineDef.Capacity; GetPeakDps(ammo, system, wDef, out PeakDps, out ShotsPerSec, out BaseDps, out AreaDps, out DetDps); DesiredProjectileSpeed = (float)(!IsBeamWeapon ? ammo.AmmoDef.Trajectory.DesiredSpeed : MaxTrajectory * MyEngineConstants.UPDATE_STEPS_PER_SECOND); Trail = ammo.AmmoDef.AmmoGraphics.Lines.Trail.Enable; }
private GyroControl _Seek(ShipControlCommons shipControl, Vector3D targetVector, Vector3D?targetUp, out double yawPitchError, out double rollError) { var angularVelocity = shipControl.AngularVelocity; if (angularVelocity == null) { // No ship controller, no action yawPitchError = rollError = Math.PI; return(shipControl.GyroControl); } Vector3D referenceForward; Vector3D referenceLeft; Vector3D referenceUp; GyroControl gyroControl; // See if local orientation is the same as the ship if (shipControl.ShipUp == ShipUp && shipControl.ShipForward == ShipForward) { // Use same reference vectors and GyroControl referenceForward = shipControl.ReferenceForward; referenceLeft = shipControl.ReferenceLeft; referenceUp = shipControl.ReferenceUp; gyroControl = shipControl.GyroControl; } else { referenceForward = GetReferenceVector(shipControl, ShipForward); referenceLeft = GetReferenceVector(shipControl, ShipLeft); referenceUp = GetReferenceVector(shipControl, ShipUp); // Need our own GyroControl instance in this case gyroControl = new GyroControl(); gyroControl.Init(shipControl.Blocks, shipUp: ShipUp, shipForward: ShipForward); } targetVector = Vector3D.Normalize(targetVector); // Invert our world matrix var toLocal = MatrixD.Transpose(MatrixD.CreateWorld(Vector3D.Zero, referenceForward, referenceUp)); // And bring targetVector & angular velocity into local space var localTarget = Vector3D.TransformNormal(-targetVector, toLocal); var localVel = Vector3D.TransformNormal((Vector3D)angularVelocity, toLocal); // Use simple trig to get the error angles var yawError = Math.Atan2(localTarget.X, localTarget.Z); var pitchError = Math.Atan2(localTarget.Y, localTarget.Z); // Set desired angular velocity var desiredYawVel = yawPID.Compute(yawError); var desiredPitchVel = pitchPID.Compute(pitchError); //shipControl.Echo(string.Format("desiredVel = {0:F3}, {1:F3}", desiredYawVel, desiredPitchVel)); // Translate to gyro outputs double gyroYaw = 0.0; if (Math.Abs(desiredYawVel) >= ControlThreshold) { gyroYaw = yawVPID.Compute(desiredYawVel - localVel.X); } double gyroPitch = 0.0; if (Math.Abs(desiredPitchVel) >= ControlThreshold) { gyroPitch = pitchVPID.Compute(desiredPitchVel - localVel.Y); } //shipControl.Echo(string.Format("yaw, pitch = {0:F3}, {1:F3}", gyroYaw, gyroPitch)); gyroControl.SetAxisVelocity(GyroControl.Yaw, (float)gyroYaw); gyroControl.SetAxisVelocity(GyroControl.Pitch, (float)gyroPitch); // Determine total yaw/pitch error yawPitchError = Math.Acos(MathHelperD.Clamp(Vector3D.Dot(targetVector, referenceForward), -1.0, 1.0)); if (targetUp != null) { // Also adjust roll by rotating targetUp vector localTarget = Vector3D.TransformNormal((Vector3D)targetUp, toLocal); rollError = Math.Atan2(localTarget.X, localTarget.Y); var desiredRollVel = rollPID.Compute(rollError); //shipControl.Echo(string.Format("desiredRollVel = {0:F3}", desiredRollVel)); double gyroRoll = 0.0; if (Math.Abs(desiredRollVel) >= ControlThreshold) { gyroRoll = rollVPID.Compute(desiredRollVel - localVel.Z); } //shipControl.Echo(string.Format("roll = {0:F3}", gyroRoll)); gyroControl.SetAxisVelocity(GyroControl.Roll, (float)gyroRoll); // Only care about absolute error rollError = Math.Abs(rollError); } else { rollError = 0.0; } return(gyroControl); }
internal void UpdatePivotPos() { if (PosChangedTick == Comp.Session.Tick || AzimuthPart?.Parent == null || ElevationPart?.Entity == null || MuzzlePart?.Entity == null || Comp.Platform.State != CorePlatform.PlatformState.Ready) { return; } var parentPart = ParentIsSubpart ? AzimuthPart.Parent : Comp.MyCube; var worldMatrix = parentPart.PositionComp.WorldMatrixRef; PosChangedTick = Comp.Session.Tick; var azimuthMatrix = AzimuthPart.Entity.PositionComp.WorldMatrixRef; var elevationMatrix = ElevationPart.Entity.PositionComp.WorldMatrixRef; var weaponCenter = MuzzlePart.Entity.PositionComp.WorldAABB.Center; BarrelOrigin = weaponCenter; var centerTestPos = azimuthMatrix.Translation; var muzzleRadius = MuzzlePart.Entity.PositionComp.LocalVolume.Radius; MyPivotUp = azimuthMatrix.Up; MyPivotFwd = elevationMatrix.Forward; if (System.TurretMovement == CoreSystem.TurretType.ElevationOnly) { Vector3D forward; var eLeft = elevationMatrix.Left; Vector3D.Cross(ref eLeft, ref MyPivotUp, out forward); WeaponConstMatrix = new MatrixD { Forward = forward, Up = MyPivotUp, Left = elevationMatrix.Left }; } else { var forward = !AlternateForward ? worldMatrix.Forward : Vector3D.TransformNormal(AzimuthInitFwdDir, worldMatrix); Vector3D left; Vector3D.Cross(ref MyPivotUp, ref forward, out left); WeaponConstMatrix = new MatrixD { Forward = forward, Up = MyPivotUp, Left = left }; } Vector3D pivotLeft; Vector3D.Cross(ref MyPivotUp, ref MyPivotFwd, out pivotLeft); if (Vector3D.IsZero(pivotLeft)) { MyPivotPos = centerTestPos; } else { Vector3D barrelUp; Vector3D.Cross(ref MyPivotFwd, ref pivotLeft, out barrelUp); var azToMuzzleOrigin = weaponCenter - centerTestPos; double azToMuzzleDot; Vector3D.Dot(ref azToMuzzleOrigin, ref barrelUp, out azToMuzzleDot); double myPivotUpDot; Vector3D.Dot(ref MyPivotUp, ref barrelUp, out myPivotUpDot); var pivotOffsetMagnitude = MathHelperD.Clamp(azToMuzzleDot / myPivotUpDot, -muzzleRadius, muzzleRadius); var pivotOffset = pivotOffsetMagnitude * MyPivotUp - (pivotOffsetMagnitude * MyPivotFwd); MyPivotPos = centerTestPos + pivotOffset; } if (!Vector3D.IsZero(AimOffset)) { var pivotRotMatrix = new MatrixD { Forward = MyPivotFwd, Left = elevationMatrix.Left, Up = elevationMatrix.Up }; Vector3D offSet; Vector3D.Rotate(ref AimOffset, ref pivotRotMatrix, out offSet); MyPivotPos += offSet; } if (!Comp.Debug) { return; } MyCenterTestLine = new LineD(centerTestPos, centerTestPos + (MyPivotUp * 20)); MyPivotTestLine = new LineD(MyPivotPos, MyPivotPos - (WeaponConstMatrix.Left * 10)); MyBarrelTestLine = new LineD(weaponCenter, weaponCenter + (MyPivotFwd * 16)); MyAimTestLine = new LineD(MyPivotPos, MyPivotPos + (MyPivotFwd * 20)); AzimuthFwdLine = new LineD(weaponCenter, weaponCenter + (WeaponConstMatrix.Forward * 19)); if (Target.HasTarget) { MyShootAlignmentLine = new LineD(MyPivotPos, Target.TargetPos); } }
internal void ResetHit() { ShrinkInited = false; TotalLength = MathHelperD.Clamp(MaxTracerLength + MaxGlowLength, 0.1f, MaxTrajectory); }