internal void AddProjectileTargets() // This calls AI late for fragments need to fix { for (int i = 0; i < AddTargets.Count; i++) { var p = AddTargets[i]; for (int t = 0; t < p.Info.Ai.TargetAis.Count; t++) { var targetAi = p.Info.Ai.TargetAis[t]; var addProjectile = p.Info.AmmoDef.Trajectory.Guidance != GuidanceType.None && targetAi.PointDefense; if (!addProjectile && targetAi.PointDefense) { if (Vector3.Dot(p.Info.Direction, p.Info.Origin - targetAi.MyGrid.PositionComp.WorldMatrixRef.Translation) < 0) { var targetSphere = targetAi.MyGrid.PositionComp.WorldVolume; targetSphere.Radius *= 3; var testRay = new RayD(p.Info.Origin, p.Info.Direction); var quickCheck = Vector3D.IsZero(targetAi.GridVel, 0.025) && targetSphere.Intersects(testRay) != null; if (!quickCheck) { var deltaPos = targetSphere.Center - p.Info.Origin; var deltaVel = targetAi.GridVel - p.Info.Ai.GridVel; var timeToIntercept = MathFuncs.Intercept(deltaPos, deltaVel, p.Info.AmmoDef.Const.DesiredProjectileSpeed); var predictedPos = targetSphere.Center + (float)timeToIntercept * deltaVel; targetSphere.Center = predictedPos; } if (quickCheck || targetSphere.Intersects(testRay) != null) { addProjectile = true; } } } if (addProjectile) { targetAi.DeadProjectiles.Remove(p); targetAi.LiveProjectile.Add(p); targetAi.LiveProjectileTick = Session.Tick; targetAi.NewProjectileTick = Session.Tick; p.Watchers.Add(targetAi); } } } AddTargets.Clear(); }
internal void ActivateMine() { var ent = Info.Target.Entity; MineActivated = true; AtMaxRange = false; var targetPos = ent.PositionComp.WorldAABB.Center; var deltaPos = targetPos - Position; var targetVel = ent.Physics?.LinearVelocity ?? Vector3.Zero; var deltaVel = targetVel - Vector3.Zero; var timeToIntercept = MathFuncs.Intercept(deltaPos, deltaVel, DesiredSpeed); var predictedPos = targetPos + (float)timeToIntercept * deltaVel; PredictedTargetPos = predictedPos; PrevTargetPos = predictedPos; PrevTargetVel = targetVel; LockedTarget = true; if (Guidance == GuidanceType.DetectFixed) { return; } Vector3D.DistanceSquared(ref Info.Origin, ref predictedPos, out DistanceToTravelSqr); Info.DistanceTraveled = 0; Info.PrevDistanceTraveled = 0; Info.Direction = Vector3D.Normalize(predictedPos - Position); AccelDir = Info.Direction; VelocityLengthSqr = 0; MaxVelocity = (Info.Direction * DesiredSpeed); MaxSpeed = MaxVelocity.Length(); MaxSpeedSqr = MaxSpeed * MaxSpeed; AccelVelocity = (Info.Direction * DeltaVelocityPerTick); if (ConstantSpeed) { Velocity = MaxVelocity; VelocityLengthSqr = MaxSpeed * MaxSpeed; } else { Velocity = AccelVelocity; } if (Guidance == GuidanceType.DetectSmart) { SmartsOn = true; MaxChaseTime = Info.ConsumableDef.Const.MaxChaseTime; if (SmartsOn && Info.ConsumableDef.Const.TargetOffSet && LockedTarget) { OffSetTarget(); OffsetSqr = Info.ConsumableDef.Trajectory.Smarts.Inaccuracy * Info.ConsumableDef.Trajectory.Smarts.Inaccuracy; } else { TargetOffSet = Vector3D.Zero; OffsetSqr = 0; } } TravelMagnitude = Velocity * StepConst; }
internal void Shoot() // Inlined due to keens mod profiler { try { var session = Comp.Session; var tick = session.Tick; var bps = System.Values.HardPoint.Loading.BarrelsPerShot; var targetable = ActiveAmmoDef.AmmoDef.Health > 0 && !ActiveAmmoDef.AmmoDef.Const.IsBeamWeapon; if (_ticksUntilShoot++ < System.DelayToFire) { if (AvCapable && System.PreFireSound && !PreFiringEmitter.IsPlaying) { StartPreFiringSound(); } if (ActiveAmmoDef.AmmoDef.Const.MustCharge || System.AlwaysFireFullBurst) { FinishBurst = true; } if (!PreFired) { var nxtMuzzle = NextMuzzle; for (int i = 0; i < bps; i++) { _muzzlesToFire.Clear(); _muzzlesToFire.Add(MuzzleIdToName[NextMuzzle]); if (i == bps) { NextMuzzle++; } nxtMuzzle = (nxtMuzzle + (System.Values.HardPoint.Loading.SkipBarrels + 1)) % _numOfBarrels; } uint prefireLength; if (System.WeaponAnimationLengths.TryGetValue(EventTriggers.PreFire, out prefireLength)) { if (_prefiredTick + prefireLength <= tick) { EventTriggerStateChanged(EventTriggers.PreFire, true, _muzzlesToFire); _prefiredTick = tick; } } PreFired = true; } return; } if (PreFired) { EventTriggerStateChanged(EventTriggers.PreFire, false); _muzzlesToFire.Clear(); PreFired = false; } if (System.HasBarrelRotation) { SpinBarrel(); if (BarrelRate < 9) { if (_spinUpTick <= tick) { BarrelRate++; _spinUpTick = tick + _ticksBeforeSpinUp; } return; } } if (ShootTick > tick) { return; } if (LockOnFireState && (Target.Entity != Comp.Ai.Focus.Target[0] || Target.Entity != Comp.Ai.Focus.Target[1])) { Comp.Ai.Focus.GetPriorityTarget(out Target.Entity); } ShootTick = tick + TicksPerShot; if (!IsShooting) { StartShooting(); } var burstDelay = (uint)System.Values.HardPoint.Loading.DelayAfterBurst; if (ActiveAmmoDef.AmmoDef.Const.BurstMode && ++State.ShotsFired > System.ShotsPerBurst) { State.ShotsFired = 1; EventTriggerStateChanged(EventTriggers.BurstReload, false); } else if (ActiveAmmoDef.AmmoDef.Const.HasShotReloadDelay && System.ShotsPerBurst > 0 && ++State.ShotsFired == System.ShotsPerBurst) { State.ShotsFired = 0; ShootTick = burstDelay > TicksPerShot ? tick + burstDelay : tick + TicksPerShot; } if (Comp.Ai.VelocityUpdateTick != tick) { Comp.Ai.GridVel = Comp.Ai.MyGrid.Physics?.LinearVelocity ?? Vector3D.Zero; Comp.Ai.IsStatic = Comp.Ai.MyGrid.Physics?.IsStatic ?? false; Comp.Ai.VelocityUpdateTick = tick; } var targetAiCnt = Comp.Ai.TargetAis.Count; Projectile vProjectile = null; if (ActiveAmmoDef.AmmoDef.Const.VirtualBeams) { vProjectile = CreateVirtualProjectile(); } for (int i = 0; i < bps; i++) { var current = NextMuzzle; var muzzle = Muzzles[current]; if (muzzle.LastUpdateTick != tick) { var dummy = Dummies[current]; var newInfo = dummy.Info; muzzle.Direction = newInfo.Direction; muzzle.Position = newInfo.Position; muzzle.LastUpdateTick = tick; } if (ActiveAmmoDef.AmmoDef.Const.Reloadable) { if (State.Sync.CurrentAmmo == 0) { break; } State.Sync.CurrentAmmo--; } if (ActiveAmmoDef.AmmoDef.Const.HasBackKickForce && !Comp.Ai.IsStatic) { Comp.Ai.MyGrid.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE, -muzzle.Direction * ActiveAmmoDef.AmmoDef.BackKickForce, muzzle.Position, Vector3D.Zero); } if (PlayTurretAv) { if (System.BarrelEffect1 && tick - muzzle.LastAv1Tick > System.Barrel1AvTicks && !muzzle.Av1Looping) { muzzle.LastAv1Tick = tick; muzzle.Av1Looping = System.Values.HardPoint.Graphics.Barrel1.Extras.Loop; session.Av.AvBarrels1.Add(new AvBarrel { Weapon = this, Muzzle = muzzle, StartTick = tick }); } if (System.BarrelEffect2 && tick - muzzle.LastAv2Tick > System.Barrel2AvTicks && !muzzle.Av2Looping) { muzzle.LastAv2Tick = tick; muzzle.Av2Looping = System.Values.HardPoint.Graphics.Barrel2.Extras.Loop; session.Av.AvBarrels2.Add(new AvBarrel { Weapon = this, Muzzle = muzzle, StartTick = tick }); } } for (int j = 0; j < System.Values.HardPoint.Loading.TrajectilesPerBarrel; j++) { if (System.Values.HardPoint.DeviateShotAngle > 0) { var dirMatrix = Matrix.CreateFromDir(muzzle.Direction); var randomFloat1 = MyUtils.GetRandomFloat(-System.Values.HardPoint.DeviateShotAngle, System.Values.HardPoint.DeviateShotAngle); var randomFloat2 = MyUtils.GetRandomFloat(0.0f, MathHelper.TwoPi); muzzle.DeviatedDir = Vector3.TransformNormal(-new Vector3( MyMath.FastSin(randomFloat1) * MyMath.FastCos(randomFloat2), MyMath.FastSin(randomFloat1) * MyMath.FastSin(randomFloat2), MyMath.FastCos(randomFloat1)), dirMatrix); } else { muzzle.DeviatedDir = muzzle.Direction; } if (ActiveAmmoDef.AmmoDef.Const.VirtualBeams && j == 0) { MyEntity primeE = null; MyEntity triggerE = null; if (ActiveAmmoDef.AmmoDef.Const.PrimeModel) { primeE = ActiveAmmoDef.AmmoDef.Const.PrimeEntityPool.Get(); } if (ActiveAmmoDef.AmmoDef.Const.TriggerModel) { triggerE = session.TriggerEntityPool.Get(); } var info = session.Projectiles.VirtInfoPool.Get(); info.InitVirtual(System, Comp.Ai, ActiveAmmoDef.AmmoDef, primeE, triggerE, Target, WeaponId, muzzle.MuzzleId, muzzle.Position, muzzle.DeviatedDir); vProjectile.VrPros.Add(new VirtualProjectile { Info = info, VisualShot = session.Av.AvShotPool.Get() }); if (!ActiveAmmoDef.AmmoDef.Const.RotateRealBeam) { vProjectile.Info.WeaponCache.VirutalId = 0; } else if (i == _nextVirtual) { vProjectile.Info.Origin = muzzle.Position; vProjectile.Info.Direction = muzzle.DeviatedDir; vProjectile.Info.WeaponCache.VirutalId = _nextVirtual; } Comp.Session.Projectiles.ActiveProjetiles.Add(vProjectile); } else { var p = Comp.Session.Projectiles.ProjectilePool.Count > 0 ? Comp.Session.Projectiles.ProjectilePool.Pop() : new Projectile(); p.Info.Id = Comp.Session.Projectiles.CurrentProjectileId++; p.Info.System = System; p.Info.Ai = Comp.Ai; p.Info.AmmoDef = ActiveAmmoDef.AmmoDef; p.Info.Overrides = Comp.Set.Value.Overrides; p.Info.Target.Entity = Target.Entity; p.Info.Target.Projectile = Target.Projectile; p.Info.Target.IsProjectile = Target.Projectile != null; p.Info.Target.IsFakeTarget = Comp.TrackReticle; p.Info.Target.FiringCube = Comp.MyCube; p.Info.WeaponId = WeaponId; p.Info.MuzzleId = muzzle.MuzzleId; p.Info.BaseDamagePool = BaseDamage; p.Info.EnableGuidance = Comp.Set.Value.Guidance; p.Info.DetonationDamage = ActiveAmmoDef.AmmoDef.Const.DetonationDamage; p.Info.AreaEffectDamage = ActiveAmmoDef.AmmoDef.Const.AreaEffectDamage; p.Info.WeaponCache = WeaponCache; p.Info.WeaponCache.VirutalId = -1; p.Info.Seed = Comp.Seed; p.Info.LockOnFireState = LockOnFireState; p.Info.ShooterVel = Comp.Ai.GridVel; p.Info.Origin = muzzle.Position; p.Info.OriginUp = MyPivotUp; p.PredictedTargetPos = Target.TargetPos; p.Info.Direction = muzzle.DeviatedDir; p.State = Projectile.ProjectileState.Start; p.Info.PrimeEntity = ActiveAmmoDef.AmmoDef.Const.PrimeModel ? ActiveAmmoDef.AmmoDef.Const.PrimeEntityPool.Get() : null; p.Info.TriggerEntity = ActiveAmmoDef.AmmoDef.Const.TriggerModel ? session.TriggerEntityPool.Get() : null; Comp.Session.Projectiles.ActiveProjetiles.Add(p); if (targetable) { for (int t = 0; t < targetAiCnt; t++) { var targetAi = Comp.Ai.TargetAis[t]; var addProjectile = ActiveAmmoDef.AmmoDef.Trajectory.Guidance != GuidanceType.None && targetAi.PointDefense; if (!addProjectile && targetAi.PointDefense) { if (Vector3.Dot(p.Info.Direction, p.Info.Origin - targetAi.MyGrid.PositionComp.WorldMatrixRef.Translation) < 0) { var targetSphere = targetAi.MyGrid.PositionComp.WorldVolume; targetSphere.Radius *= 3; var testRay = new RayD(p.Info.Origin, p.Info.Direction); var quickCheck = Vector3D.IsZero(targetAi.GridVel, 0.025) && targetSphere.Intersects(testRay) != null; if (!quickCheck) { var deltaPos = targetSphere.Center - MyPivotPos; var deltaVel = targetAi.GridVel - Comp.Ai.GridVel; var timeToIntercept = MathFuncs.Intercept(deltaPos, deltaVel, ActiveAmmoDef.AmmoDef.Const.DesiredProjectileSpeed); var predictedPos = targetSphere.Center + (float)timeToIntercept * deltaVel; targetSphere.Center = predictedPos; } if (quickCheck || targetSphere.Intersects(testRay) != null) { addProjectile = true; } } } if (addProjectile) { targetAi.LiveProjectile.Add(p); targetAi.LiveProjectileTick = tick; targetAi.NewProjectileTick = tick; p.Watchers.Add(targetAi); } } } } } _muzzlesToFire.Add(MuzzleIdToName[current]); if (HeatPShot > 0) { if (!HeatLoopRunning) { Comp.Session.FutureEvents.Schedule(UpdateWeaponHeat, null, 20); HeatLoopRunning = true; } State.Sync.Heat += HeatPShot; Comp.CurrentHeat += HeatPShot; if (State.Sync.Heat >= System.MaxHeat) { if (!Comp.Session.IsClient && Comp.Set.Value.Overload > 1) { var dmg = .02f * Comp.MaxIntegrity; Comp.Slim.DoDamage(dmg, MyDamageType.Environment, true, null, Comp.Ai.MyGrid.EntityId); } EventTriggerStateChanged(EventTriggers.Overheated, true); State.Sync.Overheated = true; StopShooting(); break; } } if (i == bps) { NextMuzzle++; } NextMuzzle = (NextMuzzle + (System.Values.HardPoint.Loading.SkipBarrels + 1)) % _numOfBarrels; } if (IsShooting) { EventTriggerStateChanged(state: EventTriggers.Firing, active: true, muzzles: _muzzlesToFire); } if (!ActiveAmmoDef.AmmoDef.Const.MustCharge && ActiveAmmoDef.AmmoDef.Const.BurstMode && (State.Sync.CurrentAmmo > 0 || ActiveAmmoDef.AmmoDef.Const.EnergyAmmo) && State.ShotsFired == System.ShotsPerBurst) { uint delay = 0; FinishBurst = false; if (System.WeaponAnimationLengths.TryGetValue(EventTriggers.Firing, out delay)) { session.FutureEvents.Schedule(o => { EventTriggerStateChanged(EventTriggers.BurstReload, true); }, null, delay); } else { EventTriggerStateChanged(EventTriggers.BurstReload, true); } if (AvCapable && RotateEmitter != null && RotateEmitter.IsPlaying) { StopRotateSound(); } if (IsShooting) { StopShooting(); } ShootTick = burstDelay > TicksPerShot ? tick + burstDelay + delay : tick + TicksPerShot + delay; } else if (((ActiveAmmoDef.AmmoDef.Const.BurstMode && System.AlwaysFireFullBurst) || ActiveAmmoDef.AmmoDef.Const.MustCharge) && State.Sync.CurrentAmmo > 0 && State.ShotsFired < System.ShotsPerBurst) { FinishBurst = true; } else if (ActiveAmmoDef.AmmoDef.Const.Reloadable && (State.Sync.CurrentAmmo == 0 || (State.ShotsFired == System.ShotsPerBurst && ActiveAmmoDef.AmmoDef.Const.MustCharge)) && !State.Sync.Reloading) { StartReload(); } if (State.ManualShoot == TerminalActionState.ShootOnce && --State.SingleShotCounter <= 0) { State.ManualShoot = TerminalActionState.ShootOff; } _muzzlesToFire.Clear(); _nextVirtual = _nextVirtual + 1 < bps ? _nextVirtual + 1 : 0; } catch (Exception e) { Log.Line($"Error in shoot: {e}"); } }