// Note: facing is only used by the legacy positioning code // The world coordinate model uses Actor.Orientation public void CheckFire(Actor self, AttackBase attack, IMove move, IFacing facing, Target target) { if (FireDelay > 0) { return; } var limitedAmmo = self.TraitOrDefault <LimitedAmmo>(); if (limitedAmmo != null && !limitedAmmo.HasAmmo()) { return; } if (!Combat.IsInRange(self.CenterLocation, Weapon.Range, target)) { return; } if (Combat.IsInRange(self.CenterLocation, Weapon.MinRange, target)) { return; } if (!IsValidAgainst(self.World, target)) { return; } var barrel = Barrels[Burst % Barrels.Length]; var destMove = target.IsActor ? target.Actor.TraitOrDefault <IMove>() : null; var muzzlePosition = self.CenterPosition + MuzzleOffset(self, barrel); var legacyMuzzlePosition = PPos.FromWPos(muzzlePosition); var legacyMuzzleAltitude = Game.CellSize * muzzlePosition.Z / 1024; var legacyFacing = MuzzleOrientation(self, barrel).Yaw.Angle / 4; var args = new ProjectileArgs { weapon = Weapon, firedBy = self, target = target, src = legacyMuzzlePosition, srcAltitude = legacyMuzzleAltitude, dest = target.CenterLocation, destAltitude = destMove != null ? destMove.Altitude : 0, facing = legacyFacing, firepowerModifier = self.TraitsImplementing <IFirepowerModifier>() .Select(a => a.GetFirepowerModifier()) .Product() }; attack.ScheduleDelayedAction(Info.FireDelay, () => { if (args.weapon.Projectile != null) { var projectile = args.weapon.Projectile.Create(args); if (projectile != null) { self.World.Add(projectile); } if (args.weapon.Report != null && args.weapon.Report.Any()) { Sound.Play(args.weapon.Report.Random(self.World.SharedRandom) + ".aud", self.CenterLocation); } } }); foreach (var na in self.TraitsImplementing <INotifyAttack>()) { na.Attacking(self, target); } Recoil = Info.Recoil; if (--Burst > 0) { FireDelay = Weapon.BurstDelay; } else { FireDelay = Weapon.ROF; Burst = Weapon.Burst; } }