protected virtual bool CanFire(Actor self, Target target) { if (IsReloading || (ammoPool != null && !ammoPool.HasAmmo())) { return(false); } if (turret != null && !turret.HasAchievedDesiredFacing) { return(false); } if ((!target.IsInRange(self.CenterPosition, MaxRange())) || (Weapon.MinRange != WDist.Zero && target.IsInRange(self.CenterPosition, Weapon.MinRange))) { return(false); } if (!Weapon.IsValidAgainst(target, self.World, self)) { return(false); } return(true); }
// Note: facing is only used by the legacy positioning code // The world coordinate model uses Actor.Orientation public Barrel CheckFire(Actor self, IFacing facing, Target target) { if (IsReloading) { return(null); } if (ammoPool != null && !ammoPool.HasAmmo()) { return(null); } if (turret != null && !turret.HasAchievedDesiredFacing) { return(null); } if (!target.IsInRange(self.CenterPosition, MaxRange())) { return(null); } if (Weapon.MinRange != WDist.Zero && target.IsInRange(self.CenterPosition, Weapon.MinRange)) { return(null); } if (!Weapon.IsValidAgainst(target, self.World, self)) { return(null); } var barrel = Barrels[Burst % Barrels.Length]; Func <WPos> muzzlePosition = () => self.CenterPosition + MuzzleOffset(self, barrel); var legacyFacing = MuzzleOrientation(self, barrel).Yaw.Angle / 4; var args = new ProjectileArgs { Weapon = Weapon, Facing = legacyFacing, DamageModifiers = self.TraitsImplementing <IFirepowerModifier>() .Select(a => a.GetFirepowerModifier()).ToArray(), InaccuracyModifiers = self.TraitsImplementing <IInaccuracyModifier>() .Select(a => a.GetInaccuracyModifier()).ToArray(), RangeModifiers = self.TraitsImplementing <IRangeModifier>() .Select(a => a.GetRangeModifier()).ToArray(), Source = muzzlePosition(), CurrentSource = muzzlePosition, SourceActor = self, PassiveTarget = target.CenterPosition, GuidedTarget = target }; 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()) { Game.Sound.Play(args.Weapon.Report.Random(self.World.SharedRandom), self.CenterPosition); } foreach (var na in self.TraitsImplementing <INotifyAttack>()) { na.Attacking(self, target, this, barrel); } Recoil = Info.Recoil; } }); if (--Burst > 0) { FireDelay = Weapon.BurstDelay; } else { var modifiers = self.TraitsImplementing <IReloadModifier>() .Select(m => m.GetReloadModifier()); FireDelay = Util.ApplyPercentageModifiers(Weapon.ReloadDelay, modifiers); Burst = Weapon.Burst; } return(barrel); }
// Note: facing is only used by the legacy positioning code // The world coordinate model uses Actor.Orientation public virtual Barrel CheckFire(Actor self, IFacing facing, Target target) { if (IsReloading) { return(null); } if (ammoPool != null && !ammoPool.HasAmmo()) { return(null); } if (turret != null && !turret.HasAchievedDesiredFacing) { return(null); } if (!target.IsInRange(self.CenterPosition, MaxRange())) { return(null); } if (Weapon.MinRange != WDist.Zero && target.IsInRange(self.CenterPosition, Weapon.MinRange)) { return(null); } if (!Weapon.IsValidAgainst(target, self.World, self)) { return(null); } if (ticksSinceLastShot >= Weapon.ReloadDelay) { Burst = Weapon.Burst; } ticksSinceLastShot = 0; var barrel = Barrels[Burst % Barrels.Length]; Func <WPos> muzzlePosition = () => self.CenterPosition + MuzzleOffset(self, barrel); var legacyFacing = MuzzleOrientation(self, barrel).Yaw.Angle / 4; var passiveTarget = Weapon.TargetActorCenter ? target.CenterPosition : target.Positions.PositionClosestTo(muzzlePosition()); var initialOffset = Weapon.FirstBurstTargetOffset; if (initialOffset != WVec.Zero) { // We want this to match Armament.LocalOffset, so we need to convert it to forward, right, up initialOffset = new WVec(initialOffset.Y, -initialOffset.X, initialOffset.Z); passiveTarget += initialOffset.Rotate(WRot.FromFacing(legacyFacing)); } var followingOffset = Weapon.FollowingBurstTargetOffset; if (followingOffset != WVec.Zero) { // We want this to match Armament.LocalOffset, so we need to convert it to forward, right, up followingOffset = new WVec(followingOffset.Y, -followingOffset.X, followingOffset.Z); passiveTarget += ((Weapon.Burst - Burst) * followingOffset).Rotate(WRot.FromFacing(legacyFacing)); } var args = new ProjectileArgs { Weapon = Weapon, Facing = legacyFacing, DamageModifiers = damageModifiers.ToArray(), InaccuracyModifiers = inaccuracyModifiers.ToArray(), RangeModifiers = rangeModifiers.ToArray(), Source = muzzlePosition(), CurrentSource = muzzlePosition, SourceActor = self, PassiveTarget = passiveTarget, GuidedTarget = target }; foreach (var na in notifyAttacks) { na.PreparingAttack(self, target, this, barrel); } 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()) { Game.Sound.Play(SoundType.World, args.Weapon.Report.Random(self.World.SharedRandom), self.CenterPosition); } if (Burst == args.Weapon.Burst && args.Weapon.StartBurstReport != null && args.Weapon.StartBurstReport.Any()) { Game.Sound.Play(SoundType.World, args.Weapon.StartBurstReport.Random(self.World.SharedRandom), self.CenterPosition); } foreach (var na in notifyAttacks) { na.Attacking(self, target, this, barrel); } Recoil = Info.Recoil; } }); if (--Burst > 0) { FireDelay = Weapon.BurstDelay; } else { var modifiers = reloadModifiers.ToArray(); FireDelay = Util.ApplyPercentageModifiers(Weapon.ReloadDelay, modifiers); Burst = Weapon.Burst; if (args.Weapon.AfterFireSound != null && args.Weapon.AfterFireSound.Any()) { ScheduleDelayedAction(Weapon.AfterFireSoundDelay, () => { Game.Sound.Play(SoundType.World, Weapon.AfterFireSound.Random(self.World.SharedRandom), self.CenterPosition); }); } foreach (var nbc in notifyBurstComplete) { nbc.FiredBurst(self, target, this); } } return(barrel); }