Пример #1
0
        private void updateGrav()
        {
            // get grav vector
            var tempGrav = MyParticlesManager.CalculateGravityInPoint(Entity.PositionComp.GetPosition());

            //MyAPIGateway.Utilities.ShowNotification(Entity.DisplayName + gravity.ToString());

            // if grav changed, flip flag, update grav
            if (tempGrav != gravity)
            {
                gravity     = tempGrav;
                updateCable = true;
            }
        }
Пример #2
0
        public Vector3D GetPredictedTargetPositionOld(Vector3D targetPos, Vector3 targetLinVel, Vector3D targetAccel)
        {
            if (Comp.Ai.VelocityUpdateTick != Comp.Session.Tick)
            {
                Comp.Ai.GridVel            = Comp.Ai.MyGrid.Physics?.LinearVelocity ?? Vector3D.Zero;
                Comp.Ai.IsStatic           = Comp.Ai.MyGrid.Physics?.IsStatic ?? false;
                Comp.Ai.VelocityUpdateTick = Comp.Session.Tick;
            }

            if (ActiveAmmoDef.AmmoDef.Const.FeelsGravity && Comp.Ai.Session.Tick - GravityTick > 119)
            {
                GravityTick  = Comp.Ai.Session.Tick;
                GravityPoint = MyParticlesManager.CalculateGravityInPoint(MyPivotPos);
            }
            var gravityMultiplier = ActiveAmmoDef.AmmoDef.Const.FeelsGravity && !MyUtils.IsZero(GravityPoint) ? ActiveAmmoDef.AmmoDef.Trajectory.GravityMultiplier : 0f;

            var predictedPos = TrajectoryEstimation(targetPos, targetLinVel, targetAccel, Comp.Session.MaxEntitySpeed, MyPivotPos, Comp.Ai.GridVel, ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed, ActiveAmmoDef.AmmoDef.Trajectory.AccelPerSec * MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS, ActiveAmmoDef.AmmoDef.Trajectory.AccelPerSec, gravityMultiplier, GravityPoint, System.Prediction != Prediction.Advanced);

            return(predictedPos);
        }
Пример #3
0
        public Vector3D GetPredictedTargetPosition(Vector3D targetPos, Vector3 targetLinVel, Vector3D targetAccel)
        {
            if (Comp.Ai.VelocityUpdateTick != Comp.Session.Tick)
            {
                Comp.Ai.GridVel            = Comp.Ai.MyGrid.Physics?.LinearVelocity ?? Vector3D.Zero;
                Comp.Ai.IsStatic           = Comp.Ai.MyGrid.Physics?.IsStatic ?? false;
                Comp.Ai.VelocityUpdateTick = Comp.Session.Tick;
            }

            var gravityMultiplier = 0f;
            var gravityPoint      = Vector3D.Zero;

            if (ActiveAmmoDef.AmmoDef.Const.FeelsGravity)
            {
                gravityMultiplier = ActiveAmmoDef.AmmoDef.Trajectory.GravityMultiplier;
                gravityPoint      = MyParticlesManager.CalculateGravityInPoint(MyPivotPos);
            }
            var predictedPos = TrajectoryEstimation(targetPos, targetLinVel, targetAccel, Comp.Session.MaxEntitySpeed, MyPivotPos, Comp.Ai.GridVel, ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed, 0, ActiveAmmoDef.AmmoDef.Trajectory.AccelPerSec, gravityMultiplier, gravityPoint, System.Prediction != Prediction.Advanced);

            return(predictedPos);
        }
Пример #4
0
        internal static Vector3D TrajectoryEstimation(Weapon weapon, Vector3D targetPos, Vector3D targetVel, Vector3D targetAcc, out bool valid)
        {
            valid = true;
            var ai      = weapon.Comp.Ai;
            var session = ai.Session;
            var ammoDef = weapon.ActiveAmmoDef.AmmoDef;

            if (ai.VelocityUpdateTick != session.Tick)
            {
                ai.GridVel            = ai.MyGrid.Physics?.LinearVelocity ?? Vector3D.Zero;
                ai.IsStatic           = ai.MyGrid.Physics?.IsStatic ?? false;
                ai.VelocityUpdateTick = session.Tick;
            }

            if (ammoDef.Const.FeelsGravity && session.Tick - weapon.GravityTick > 119)
            {
                weapon.GravityTick  = session.Tick;
                weapon.GravityPoint = MyParticlesManager.CalculateGravityInPoint(weapon.MyPivotPos);
            }

            var gravityMultiplier = ammoDef.Const.FeelsGravity && !MyUtils.IsZero(weapon.GravityPoint) ? ammoDef.Trajectory.GravityMultiplier : 0f;
            var targetMaxSpeed    = weapon.Comp.Session.MaxEntitySpeed;
            var shooterPos        = weapon.MyPivotPos;

            var      shooterVel          = (Vector3D)weapon.Comp.Ai.GridVel;
            var      projectileMaxSpeed  = ammoDef.Const.DesiredProjectileSpeed;
            var      projectileInitSpeed = ammoDef.Trajectory.AccelPerSec * MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS;
            var      projectileAccMag    = ammoDef.Trajectory.AccelPerSec;
            var      gravity             = weapon.GravityPoint;
            var      basic    = weapon.System.Prediction != Prediction.Advanced;
            Vector3D deltaPos = targetPos - shooterPos;
            Vector3D deltaVel = targetVel - shooterVel;
            Vector3D deltaPosNorm;

            if (Vector3D.IsZero(deltaPos))
            {
                deltaPosNorm = Vector3D.Zero;
            }
            else if (Vector3D.IsUnit(ref deltaPos))
            {
                deltaPosNorm = deltaPos;
            }
            else
            {
                Vector3D.Normalize(ref deltaPos, out deltaPosNorm);
            }

            double closingSpeed;

            Vector3D.Dot(ref deltaVel, ref deltaPosNorm, out closingSpeed);

            Vector3D closingVel            = closingSpeed * deltaPosNorm;
            Vector3D lateralVel            = deltaVel - closingVel;
            double   projectileMaxSpeedSqr = projectileMaxSpeed * projectileMaxSpeed;
            double   ttiDiff = projectileMaxSpeedSqr - lateralVel.LengthSquared();

            if (ttiDiff < 0)
            {
                valid = false;
                return(targetPos);
            }

            double projectileClosingSpeed = Math.Sqrt(ttiDiff) - closingSpeed;

            double closingDistance;

            Vector3D.Dot(ref deltaPos, ref deltaPosNorm, out closingDistance);

            double timeToIntercept = ttiDiff < 0 ? 0 : closingDistance / projectileClosingSpeed;

            if (timeToIntercept < 0)
            {
                valid = false;
                return(targetPos);
            }

            double maxSpeedSqr           = targetMaxSpeed * targetMaxSpeed;
            double shooterVelScaleFactor = 1;
            bool   projectileAccelerates = projectileAccMag > 1e-6;
            bool   hasGravity            = gravityMultiplier > 1e-6;

            if (!basic && projectileAccelerates)
            {
                shooterVelScaleFactor = Math.Min(1, (projectileMaxSpeed - projectileInitSpeed) / projectileAccMag);
            }

            Vector3D estimatedImpactPoint = targetPos + timeToIntercept * (targetVel - shooterVel * shooterVelScaleFactor);

            if (basic)
            {
                return(estimatedImpactPoint);
            }
            Vector3D aimDirection = estimatedImpactPoint - shooterPos;

            Vector3D projectileVel = shooterVel;
            Vector3D projectilePos = shooterPos;

            Vector3D aimDirectionNorm;

            if (projectileAccelerates)
            {
                if (Vector3D.IsZero(deltaPos))
                {
                    aimDirectionNorm = Vector3D.Zero;
                }
                else if (Vector3D.IsUnit(ref deltaPos))
                {
                    aimDirectionNorm = aimDirection;
                }
                else
                {
                    aimDirectionNorm = Vector3D.Normalize(aimDirection);
                }
                projectileVel += aimDirectionNorm * projectileInitSpeed;
            }
            else
            {
                if (targetAcc.LengthSquared() < 1 && !hasGravity)
                {
                    return(estimatedImpactPoint);
                }

                if (Vector3D.IsZero(deltaPos))
                {
                    aimDirectionNorm = Vector3D.Zero;
                }
                else if (Vector3D.IsUnit(ref deltaPos))
                {
                    aimDirectionNorm = aimDirection;
                }
                else
                {
                    Vector3D.Normalize(ref aimDirection, out aimDirectionNorm);
                }
                projectileVel += aimDirectionNorm * projectileMaxSpeed;
            }

            var count = projectileAccelerates ? 600 : 60;

            double   dt                = Math.Max(MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS, timeToIntercept / count); // This can be a const somewhere
            double   dtSqr             = dt * dt;
            Vector3D targetAccStep     = targetAcc * dt;
            Vector3D projectileAccStep = aimDirectionNorm * projectileAccMag * dt;
            Vector3D gravityStep       = gravity * gravityMultiplier * dt;
            Vector3D aimOffset         = Vector3D.Zero;
            double   minDiff           = double.MaxValue;

            for (int i = 0; i < count; ++i)
            {
                targetVel += targetAccStep;

                if (targetVel.LengthSquared() > maxSpeedSqr)
                {
                    Vector3D targetNormVel;
                    Vector3D.Normalize(ref targetVel, out targetNormVel);
                    targetVel = targetNormVel * targetMaxSpeed;
                }

                targetPos += targetVel * dt;
                if (projectileAccelerates)
                {
                    projectileVel += projectileAccStep;
                    if (projectileVel.LengthSquared() > projectileMaxSpeedSqr)
                    {
                        Vector3D pNormVel;
                        Vector3D.Normalize(ref projectileVel, out pNormVel);
                        projectileVel = pNormVel * projectileMaxSpeed;
                    }
                }

                if (hasGravity)
                {
                    projectileVel += gravityStep;
                }

                projectilePos += projectileVel * dt;
                Vector3D diff      = (targetPos - projectilePos);
                double   diffLenSq = diff.LengthSquared();
                if (diffLenSq < projectileMaxSpeedSqr * dtSqr)
                {
                    aimOffset = diff;
                    break;
                }
                if (diffLenSq < minDiff)
                {
                    minDiff   = diffLenSq;
                    aimOffset = diff;
                }
            }
            return(estimatedImpactPoint + aimOffset);
        }
Пример #5
0
        private void UpdateState()
        {
            foreach (var p in ActiveProjetiles)
            {
                p.Info.Age++;
                p.Active = false;
                switch (p.State)
                {
                case ProjectileState.Destroy:
                    p.DestroyProjectile();
                    continue;

                case ProjectileState.Dead:
                    continue;

                case ProjectileState.Start:
                    p.Start();
                    break;

                case ProjectileState.OneAndDone:
                case ProjectileState.Depleted:
                case ProjectileState.Detonate:
                    p.ProjectileClose();
                    continue;
                }
                if (p.Info.Target.IsProjectile)
                {
                    if (p.Info.Target.Projectile.State != ProjectileState.Alive)
                    {
                        p.UnAssignProjectile(true);
                    }
                }

                if (p.FeelsGravity)
                {
                    var update = p.FakeGravityNear || p.EntitiesNear || p.Info.Ai.InPlanetGravity && p.Info.Age % 30 == 0 || !p.Info.Ai.InPlanetGravity && p.Info.Age % 10 == 0;
                    if (update)
                    {
                        p.Gravity = MyParticlesManager.CalculateGravityInPoint(p.Position);

                        if (!p.Info.Ai.InPlanetGravity && !MyUtils.IsZero(p.Gravity))
                        {
                            p.FakeGravityNear = true;
                        }
                        else
                        {
                            p.FakeGravityNear = false;
                        }
                    }
                    p.Velocity += (p.Gravity * p.Info.AmmoDef.Trajectory.GravityMultiplier) * Projectile.StepConst;
                    Vector3D.Normalize(ref p.Velocity, out p.Info.Direction);
                }

                if (p.AccelLength > 0 && !p.Info.TriggeredPulse)
                {
                    if (p.SmartsOn)
                    {
                        p.RunSmart();
                    }
                    else
                    {
                        var      accel = true;
                        Vector3D newVel;
                        if (p.FieldTime > 0)
                        {
                            var distToMax = p.Info.MaxTrajectory - p.Info.DistanceTraveled;

                            var stopDist = p.VelocityLengthSqr / 2 / (p.StepPerSec);
                            if (distToMax <= stopDist)
                            {
                                accel = false;
                            }

                            newVel = accel ? p.Velocity + p.AccelVelocity : p.Velocity - p.AccelVelocity;
                            p.VelocityLengthSqr = newVel.LengthSquared();

                            if (accel && p.VelocityLengthSqr > p.MaxSpeedSqr)
                            {
                                newVel = p.Info.Direction * p.MaxSpeed;
                            }
                            else if (!accel && distToMax <= 0)
                            {
                                newVel = Vector3D.Zero;
                                p.VelocityLengthSqr = 0;
                            }
                        }
                        else
                        {
                            newVel = p.Velocity + p.AccelVelocity;
                            p.VelocityLengthSqr = newVel.LengthSquared();
                            if (p.VelocityLengthSqr > p.MaxSpeedSqr)
                            {
                                newVel = p.Info.Direction * p.MaxSpeed;
                            }
                        }

                        p.Velocity = newVel;
                    }
                }

                if (p.State == ProjectileState.OneAndDone)
                {
                    p.LastPosition = p.Position;
                    var beamEnd = p.Position + (p.Info.Direction * p.Info.MaxTrajectory);
                    p.TravelMagnitude = p.Position - beamEnd;
                    p.Position        = beamEnd;
                }
                else
                {
                    if (p.ConstantSpeed || p.VelocityLengthSqr > 0)
                    {
                        p.LastPosition = p.Position;
                    }

                    p.TravelMagnitude = p.Velocity * StepConst;
                    p.Position       += p.TravelMagnitude;
                }

                p.Info.PrevDistanceTraveled = p.Info.DistanceTraveled;
                p.Info.DistanceTraveled    += Math.Abs(Vector3D.Dot(p.Info.Direction, p.Velocity * StepConst));
                if (p.ModelState == EntityState.Exists)
                {
                    var     up = MatrixD.Identity.Up;
                    MatrixD matrix;
                    MatrixD.CreateWorld(ref p.Position, ref p.Info.VisualDir, ref up, out matrix);
                    if (p.Info.AmmoDef.Const.PrimeModel)
                    {
                        p.Info.AvShot.PrimeMatrix = matrix;
                    }
                    if (p.Info.AmmoDef.Const.TriggerModel && p.Info.TriggerGrowthSteps < p.Info.AmmoDef.Const.AreaEffectSize)
                    {
                        p.Info.TriggerMatrix = matrix;
                    }

                    if (p.EnableAv && p.AmmoEffect != null && p.Info.AmmoDef.Const.AmmoParticle && p.Info.AmmoDef.Const.PrimeModel)
                    {
                        var offVec = p.Position + Vector3D.Rotate(p.Info.AmmoDef.AmmoGraphics.Particles.Ammo.Offset, p.Info.AvShot.PrimeMatrix);
                        p.AmmoEffect.WorldMatrix = p.Info.AvShot.PrimeMatrix;
                        p.AmmoEffect.SetTranslation(ref offVec);
                    }
                }
                else if (p.EnableAv && p.AmmoEffect != null && p.Info.AmmoDef.Const.AmmoParticle)
                {
                    var translation = p.AmmoEffect.WorldMatrix.Translation + p.TravelMagnitude;
                    p.AmmoEffect.SetTranslation(ref translation);
                }

                if (p.DynamicGuidance)
                {
                    if (p.PruningProxyId != -1)
                    {
                        var          sphere = new BoundingSphereD(p.Position, p.Info.AmmoDef.Const.AreaEffectSize);
                        BoundingBoxD result;
                        BoundingBoxD.CreateFromSphere(ref sphere, out result);
                        Session.ProjectileTree.MoveProxy(p.PruningProxyId, ref result, p.Velocity);
                    }
                }

                if (p.State != ProjectileState.OneAndDone)
                {
                    if (!p.SmartsOn && p.Info.Age > p.Info.AmmoDef.Const.MaxLifeTime)
                    {
                        p.DistanceToTravelSqr = p.Info.DistanceTraveled * p.Info.DistanceTraveled;
                        p.EarlyEnd            = true;
                    }

                    if (p.Info.DistanceTraveled * p.Info.DistanceTraveled >= p.DistanceToTravelSqr)
                    {
                        p.AtMaxRange = true;
                        if (p.FieldTime > 0)
                        {
                            p.FieldTime--;
                            if (p.Info.AmmoDef.Const.IsMine && !p.MineSeeking && !p.MineActivated)
                            {
                                if (p.EnableAv)
                                {
                                    p.Info.AvShot.Cloaked = p.Info.AmmoDef.Trajectory.Mines.Cloak;
                                }
                                p.MineSeeking = true;
                            }
                        }
                    }
                }
                else
                {
                    p.AtMaxRange = true;
                }
                if (p.Info.AmmoDef.Const.Ewar)
                {
                    p.RunEwar();
                }

                p.Active = true;
            }
        }
Пример #6
0
        private void GenProjectiles()
        {
            for (int i = 0; i < NewProjectiles.Count; i++)
            {
                var gen          = NewProjectiles[i];
                var w            = gen.Weapon;
                var a            = gen.AmmoDef;
                var t            = gen.Type;
                var virts        = gen.NewVirts;
                var muzzle       = gen.Muzzle;
                var firingPlayer = w.Comp.Data.Repo.Base.State.PlayerId == w.Comp.Session.PlayerId || w.ClientStaticShot;
                w.ClientStaticShot = false;

                var patternCycle = gen.PatternCycle;
                var targetable   = w.ActiveAmmoDef.AmmoDef.Health > 0 && !w.ActiveAmmoDef.AmmoDef.Const.IsBeamWeapon;
                var p            = Session.Projectiles.ProjectilePool.Count > 0 ? Session.Projectiles.ProjectilePool.Pop() : new Projectile();
                p.Info.Id                  = Session.Projectiles.CurrentProjectileId++;
                p.Info.System              = w.System;
                p.Info.Ai                  = w.Comp.Ai;
                p.Info.IsFiringPlayer      = firingPlayer;
                p.Info.ClientSent          = t == Kind.Client;
                p.Info.AmmoDef             = a;
                p.Info.Overrides           = w.Comp.Data.Repo.Base.Set.Overrides;
                p.Info.Target.Entity       = t != Kind.Client ? w.Target.Entity : gen.TargetEnt;
                p.Info.Target.Projectile   = w.Target.Projectile;
                p.Info.Target.IsProjectile = w.Target.Projectile != null;
                p.Info.Target.IsFakeTarget = w.Comp.Data.Repo.Base.State.TrackingReticle;
                p.Info.Target.FiringCube   = w.Comp.MyCube;

                p.Info.DummyTarget = w.Comp.Data.Repo.Base.State.TrackingReticle ? w.Comp.Session.PlayerDummyTargets[w.Comp.Data.Repo.Base.State.PlayerId] : null;

                p.Info.WeaponId        = w.WeaponId;
                p.Info.BaseDamagePool  = a == w.ActiveAmmoDef.AmmoDef ? w.BaseDamage : a.BaseDamage;
                p.Info.EnableGuidance  = w.Comp.Data.Repo.Base.Set.Guidance;
                p.Info.WeaponCache     = w.WeaponCache;
                p.Info.WeaponRng       = w.TargetData.WeaponRandom;
                p.Info.LockOnFireState = w.LockOnFireState;
                p.Info.ShooterVel      = w.Comp.Ai.GridVel;

                p.Info.OriginUp              = t != Kind.Client ? w.MyPivotUp : gen.OriginUp;
                p.Info.MaxTrajectory         = t != Kind.Client ? a.Const.MaxTrajectoryGrows && w.FireCounter < a.Trajectory.MaxTrajectoryTime ? a.Const.TrajectoryStep * w.FireCounter : a.Const.MaxTrajectory : gen.MaxTrajectory;
                p.Info.MuzzleId              = t != Kind.Virtual ? muzzle.MuzzleId : -1;
                p.Info.UniqueMuzzleId        = muzzle.UniqueId;
                p.Info.WeaponCache.VirutalId = t != Kind.Virtual ? -1 : p.Info.WeaponCache.VirutalId;
                p.Info.Origin    = t != Kind.Client ? t != Kind.Virtual ? muzzle.Position : w.MyPivotPos : gen.Origin;
                p.Info.Direction = t != Kind.Client ? t != Kind.Virtual ? muzzle.DeviatedDir : w.MyPivotDir : gen.Direction;
                if (t == Kind.Client)
                {
                    p.Velocity = gen.Velocity;
                }

                float shotFade;
                if (a.Const.HasShotFade && !a.Const.VirtualBeams)
                {
                    if (patternCycle > a.AmmoGraphics.Lines.Tracer.VisualFadeStart)
                    {
                        shotFade = MathHelper.Clamp(((patternCycle - a.AmmoGraphics.Lines.Tracer.VisualFadeStart)) * a.Const.ShotFadeStep, 0, 1);
                    }
                    else if (w.System.DelayCeaseFire && w.CeaseFireDelayTick != Session.Tick)
                    {
                        shotFade = MathHelper.Clamp(((Session.Tick - w.CeaseFireDelayTick) - a.AmmoGraphics.Lines.Tracer.VisualFadeStart) * a.Const.ShotFadeStep, 0, 1);
                    }
                    else
                    {
                        shotFade = 0;
                    }
                }
                else
                {
                    shotFade = 0;
                }
                p.Info.ShotFade      = shotFade;
                p.PredictedTargetPos = w.Target.TargetPos;
                p.DeadSphere.Center  = w.MyPivotPos;
                p.DeadSphere.Radius  = w.Comp.Ai.MyGrid.GridSizeHalf + 0.1;

                if (a.Const.FeelsGravity && w.System.Session.Tick - w.GravityTick > 60)
                {
                    w.GravityTick  = w.System.Session.Tick;
                    w.GravityPoint = MyParticlesManager.CalculateGravityInPoint(p.Info.Origin);
                }

                p.Gravity = w.GravityPoint;
                if (t != Kind.Virtual)
                {
                    p.Info.PrimeEntity   = a.Const.PrimeModel ? a.Const.PrimeEntityPool.Get() : null;
                    p.Info.TriggerEntity = a.Const.TriggerModel ? Session.TriggerEntityPool.Get() : null;

                    if (targetable)
                    {
                        Session.Projectiles.AddTargets.Add(p);
                    }
                }
                else
                {
                    p.Info.WeaponCache.VirtualHit       = false;
                    p.Info.WeaponCache.Hits             = 0;
                    p.Info.WeaponCache.HitEntity.Entity = null;
                    for (int j = 0; j < virts.Count; j++)
                    {
                        var v = virts[j];
                        p.VrPros.Add(v.Info);
                        if (!a.Const.RotateRealBeam)
                        {
                            p.Info.WeaponCache.VirutalId = 0;
                        }
                        else if (v.Rotate)
                        {
                            p.Info.Origin                = v.Muzzle.Position;
                            p.Info.Direction             = v.Muzzle.Direction;
                            p.Info.WeaponCache.VirutalId = v.VirtualId;
                        }
                    }
                    virts.Clear();
                    VirtInfoPools.Return(virts);
                }

                Session.Projectiles.ActiveProjetiles.Add(p);
                p.Start();

                p.Info.Monitors = w.Monitors;
                if (p.Info.Monitors?.Count > 0)
                {
                    Session.MonitoredProjectiles[p.Info.Id] = p;
                    for (int j = 0; j < p.Info.Monitors.Count; j++)
                    {
                        p.Info.Monitors[j].Invoke(w.Comp.MyCube.EntityId, w.WeaponId, p.Info.Id, p.Info.Target.TargetId, p.Position, true);
                    }
                }
            }
            NewProjectiles.Clear();
        }
Пример #7
0
        private void UpdateState(int end = 0)
        {
            for (int i = ActiveProjetiles.Count - 1; i >= end; i--)
            {
                var p = ActiveProjetiles[i];
                ++p.Info.Age;
                ++p.Info.Ai.MyProjectiles;
                p.Info.Ai.ProjectileTicker = p.Info.System.Session.Tick;

                switch (p.State)
                {
                case ProjectileState.Destroy:
                    p.DestroyProjectile();
                    continue;

                case ProjectileState.Dead:
                    continue;

                case ProjectileState.OneAndDone:
                case ProjectileState.Depleted:
                case ProjectileState.Detonate:
                    if (p.Info.Age == 0 && p.State == ProjectileState.OneAndDone)
                    {
                        break;
                    }

                    p.ProjectileClose();
                    ProjectilePool.Push(p);
                    ActiveProjetiles.RemoveAtFast(i);
                    continue;
                }

                if (p.Info.Target.IsProjectile)
                {
                    if (p.Info.Target.Projectile.State != ProjectileState.Alive)
                    {
                        p.UnAssignProjectile(true);
                    }
                }

                if (!p.AtMaxRange)
                {
                    if (p.FeelsGravity)
                    {
                        var update = (p.Info.Age % 60 == 0 || (p.FakeGravityNear || p.EntitiesNear) && p.Info.Age % 10 == 0) && p.Info.Age > 0;
                        if (update)
                        {
                            p.Gravity = MyParticlesManager.CalculateGravityInPoint(p.Position);
                            if (!p.Info.InPlanetGravity && !MyUtils.IsZero(p.Gravity))
                            {
                                p.FakeGravityNear = true;
                            }
                            else
                            {
                                p.FakeGravityNear = false;
                            }
                            p.EntitiesNear = false;
                        }
                        p.Velocity += (p.Gravity * p.Info.AmmoDef.Trajectory.GravityMultiplier) * Projectile.StepConst;
                        Vector3D.Normalize(ref p.Velocity, out p.Info.Direction);
                    }

                    if (p.DeltaVelocityPerTick > 0 && !p.Info.EwarAreaPulse)
                    {
                        if (p.SmartsOn)
                        {
                            p.RunSmart();
                        }
                        else
                        {
                            var      accel = true;
                            Vector3D newVel;
                            if (p.FieldTime > 0)
                            {
                                var distToMax = p.Info.MaxTrajectory - p.Info.DistanceTraveled;

                                var stopDist = p.VelocityLengthSqr / 2 / (p.AccelInMetersPerSec);
                                if (distToMax <= stopDist)
                                {
                                    accel = false;
                                }

                                newVel = accel ? p.Velocity + p.AccelVelocity : p.Velocity - p.AccelVelocity;
                                p.VelocityLengthSqr = newVel.LengthSquared();

                                if (accel && p.VelocityLengthSqr > p.MaxSpeedSqr)
                                {
                                    newVel = p.Info.Direction * p.MaxSpeed;
                                }
                                else if (!accel && distToMax <= 0)
                                {
                                    newVel = Vector3D.Zero;
                                    p.VelocityLengthSqr = 0;
                                }
                            }
                            else
                            {
                                newVel = p.Velocity + p.AccelVelocity;
                                p.VelocityLengthSqr = newVel.LengthSquared();
                                if (p.VelocityLengthSqr > p.MaxSpeedSqr)
                                {
                                    newVel = p.Info.Direction * p.MaxSpeed;
                                }
                            }

                            p.Velocity = newVel;
                        }
                    }

                    if (p.State == ProjectileState.OneAndDone)
                    {
                        p.LastPosition = p.Position;
                        var beamEnd = p.Position + (p.Info.Direction * p.Info.MaxTrajectory);
                        p.TravelMagnitude = p.Position - beamEnd;
                        p.Position        = beamEnd;
                    }
                    else
                    {
                        if (p.ConstantSpeed || p.VelocityLengthSqr > 0)
                        {
                            p.LastPosition = p.Position;
                        }

                        p.TravelMagnitude = p.Info.Age != 0 ? p.Velocity * StepConst : p.InitalStep;
                        p.Position       += p.TravelMagnitude;
                    }

                    p.Info.PrevDistanceTraveled = p.Info.DistanceTraveled;

                    double distChanged;
                    Vector3D.Dot(ref p.Info.Direction, ref p.TravelMagnitude, out distChanged);
                    p.Info.DistanceTraveled += Math.Abs(distChanged);
                    if (p.Info.DistanceTraveled <= 500)
                    {
                        ++p.Info.Ai.ProInMinCacheRange;
                    }

                    if (p.DynamicGuidance)
                    {
                        if (p.PruningProxyId != -1)
                        {
                            var          sphere = new BoundingSphereD(p.Position, p.Info.AmmoDef.Const.AreaEffectSize);
                            BoundingBoxD result;
                            BoundingBoxD.CreateFromSphere(ref sphere, out result);
                            Session.ProjectileTree.MoveProxy(p.PruningProxyId, ref result, p.Velocity);
                        }
                    }
                }
                if (p.ModelState == EntityState.Exists)
                {
                    var     up = MatrixD.Identity.Up;
                    MatrixD matrix;
                    MatrixD.CreateWorld(ref p.Position, ref p.Info.VisualDir, ref up, out matrix);

                    if (p.Info.AmmoDef.Const.PrimeModel)
                    {
                        p.Info.AvShot.PrimeMatrix = matrix;
                    }
                    if (p.Info.AmmoDef.Const.TriggerModel && p.Info.TriggerGrowthSteps < p.Info.AmmoDef.Const.AreaEffectSize)
                    {
                        p.Info.TriggerMatrix = matrix;
                    }
                }

                if (p.State != ProjectileState.OneAndDone)
                {
                    if (p.Info.Age > p.Info.AmmoDef.Const.MaxLifeTime)
                    {
                        p.DistanceToTravelSqr = p.Info.DistanceTraveled * p.Info.DistanceTraveled;
                        p.EarlyEnd            = true;
                    }

                    if (p.Info.DistanceTraveled * p.Info.DistanceTraveled >= p.DistanceToTravelSqr)
                    {
                        p.AtMaxRange = !p.MineSeeking;
                        if (p.FieldTime > 0)
                        {
                            p.FieldTime--;
                            if (p.Info.AmmoDef.Const.IsMine && !p.MineSeeking && !p.MineActivated)
                            {
                                if (p.EnableAv)
                                {
                                    p.Info.AvShot.Cloaked = p.Info.AmmoDef.Trajectory.Mines.Cloak;
                                }
                                p.MineSeeking = true;
                            }
                        }
                    }
                }
                else
                {
                    p.AtMaxRange = true;
                }

                if (p.Info.AmmoDef.Const.Ewar)
                {
                    p.RunEwar();
                }
            }
        }
Пример #8
0
        public void Update()
        {
            if (_targetHit)
            {
                Kill();
                return;
            }

            // Update velocity due to gravity
            Vector3D totalGravity      = MyParticlesManager.CalculateGravityInPoint(_position); // Does this get affected by artificial grav? If so... cooooool
            Vector3D naturalGravity    = RailgunCore.GetNaturalGravityAtPoint(_position);
            Vector3D artificialGravity = totalGravity - naturalGravity;

            _velocity += (naturalGravity * RailgunCore.MyConfig.NaturalGravityMultiplier + artificialGravity * RailgunCore.MyConfig.ArtificialGravityMultiplier) * _tick;

            // Update direction if velocity has changed
            if (!_velocity.Equals(_lastVelocity, 1e-3))
            {
                _direction = Vector3D.Normalize(_velocity);
            }

            _lastVelocity = _velocity;

            // Update position
            _position += _velocity * _tick;
            var _toOrigin = _position - _origin;

            //draw tracer line
            if (_drawTrail && _currentTracerFadeTicks < _maxTracerFadeTicks)
            {
                _lineColor *= _trailColorDecayRatio;
                _currentTracerFadeTicks++;
            }

            if (_toOrigin.LengthSquared() > _maxTrajectory * _maxTrajectory)
            {
                MyLog.Default.WriteLine(">> Max range hit");

                _targetHit   = true;
                _hitPosition = _position;
                Kill();
                if (_shouldExplode)
                {
                    CreateExplosion(_position, _direction, _explosionRadius, _explosionDamage);
                }
                return;
            }

            _checkIntersectionIndex = ++_checkIntersectionIndex % 5;
            if (_checkIntersectionIndex != 0 && _positionChecked)
            {
                return;
            }

            // Add current position to trajectory list
            _trajectoryPoints.Add(_position);

            var to   = _position; //_position + 5.0 * _velocity * _tick;
            var from = _lastPositionChecked;

            _positionChecked     = true;
            _lastPositionChecked = _position;

            IHitInfo hitInfo;
            bool     hit = false;

            if (Vector3D.DistanceSquared(to, from) > 50 * 50)
            {
                // Use faster raycast if ray is long enough
                hit = MyAPIGateway.Physics.CastLongRay(from, to, out hitInfo, true);
            }
            else
            {
                hit = MyAPIGateway.Physics.CastRay(from, to, out hitInfo, 0);
            }

            if (hit)
            {
                MyLog.Default.WriteLine(">> Raycast hit");
                _hitPosition = hitInfo.Position + -0.5 * _direction;
                if ((_hitPosition - _origin).LengthSquared() > _minimumArmDistance * _minimumArmDistance) //only explode if beyond arm distance
                {
                    if (_shouldExplode)
                    {
                        CreateExplosion(_hitPosition, _direction, _explosionRadius, _explosionDamage);
                    }

                    if (_shouldPenetrate)
                    {
                        GetObjectsToPenetrate(_hitPosition, _hitPosition + _direction * _penetrationRange);
                    }

                    _targetHit = true;
                    Kill();
                }
                else
                {
                    _targetHit   = true;
                    _hitPosition = _position;
                    Kill();
                }
                return;
            }

            // implied else
            var line = new LineD(from, to);

            MyGamePruningStructure.GetVoxelMapsOverlappingRay(ref line, _voxelOverlap);
            foreach (var result in _voxelOverlap)
            {
                MatrixD matrix;
                MatrixD matrixInv;
                Vector3 sizeInMetersHalf;

                MyPlanet    planet   = result.Element as MyPlanet;
                IMyVoxelMap voxelMap = result.Element as IMyVoxelMap;
                if (planet == null && voxelMap == null)
                {
                    continue;
                }

                if (planet != null)
                {
                    matrix           = planet.WorldMatrix;
                    matrixInv        = planet.PositionComp.WorldMatrixInvScaled;
                    sizeInMetersHalf = planet.SizeInMetresHalf;
                }
                else
                {
                    matrix           = voxelMap.WorldMatrix;
                    matrixInv        = voxelMap.PositionComp.WorldMatrixInvScaled;
                    sizeInMetersHalf = new Vector3(voxelMap.Storage.Size) * 0.5f;
                }

                Vector3 localTo;
                Vector3 localFrom;
                MyVoxelCoordSystems.WorldPositionToLocalPosition(from, matrix, matrixInv, sizeInMetersHalf, out localFrom);
                MyVoxelCoordSystems.WorldPositionToLocalPosition(to, matrix, matrixInv, sizeInMetersHalf, out localTo);
                var localLine = new LineD(localFrom, localTo);

                if (planet != null && ((IMyStorage)(planet.Storage)).Intersect(ref localLine))
                {
                    MyLog.Default.WriteLine(">> Railgun projectile hit planet");
                    _hitPosition = _position;
                    _targetHit   = true;
                    Kill();
                    return;
                }

                // This is very broken
                //if (voxelMap != null && ((IMyStorage)(voxelMap.Storage)).Intersect(ref localLine))
                //{
                //    MyLog.Default.WriteLine(">> Railgun projectile hit voxel");
                //    _hitPosition = _position;
                //    _targetHit = true;
                //    Kill();
                //    return;
                //}
            }
        }