예제 #1
0
        static float GetDamageToInflict(WPos pos, Actor target, WarheadInfo warhead, WeaponInfo weapon, float modifier, bool withFalloff)
        {
            // don't hit air units with splash from ground explosions, etc
            if (!weapon.IsValidAgainst(target))
            {
                return(0);
            }

            var healthInfo = target.Info.Traits.GetOrDefault <HealthInfo>();

            if (healthInfo == null)
            {
                return(0);
            }

            var rawDamage = (float)warhead.Damage;

            if (withFalloff)
            {
                var distance = (int)Math.Max(0, (target.CenterPosition - pos).Length * Game.CellSize / 1024 - healthInfo.Radius);
                var falloff  = (float)GetDamageFalloff(distance / warhead.Spread);
                rawDamage = (float)(falloff * rawDamage);
            }
            return((float)(rawDamage * modifier * (float)warhead.EffectivenessAgainst(target.Info)));
        }
예제 #2
0
파일: Armament.cs 프로젝트: reaperrr/OpenRA
        protected virtual bool CanFire(Actor self, Target target)
        {
            if (IsReloading || IsTraitPaused)
            {
                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);
        }
예제 #3
0
        bool WormAttack(Actor worm)
        {
            var targetLocation = target.Actor.Location;

            // The target has moved too far away
            if ((location - targetLocation).Length > NearEnough)
            {
                return(false);
            }

            var lunch = worm.World.ActorMap.GetUnitsAt(targetLocation)
                        .Where(t => !t.Equals(worm) && weapon.IsValidAgainst(t, worm));

            if (!lunch.Any())
            {
                return(false);
            }

            stance = AttackState.EmergingAboveGround;
            sandworm.IsAttacking = true;

            foreach (var actor in lunch)
            {
                var actor1 = actor;                     // loop variable in closure hazard

                actor.World.AddFrameEndTask(_ =>
                {
                    actor1.Destroy();

                    // Harvester insurance
                    if (!actor1.HasTrait <Harvester>())
                    {
                        return;
                    }

                    var insurance = actor1.Owner.PlayerActor.TraitOrDefault <HarvesterInsurance>();

                    if (insurance != null)
                    {
                        actor1.World.AddFrameEndTask(__ => insurance.TryActivate());
                    }
                });
            }

            positionable.SetPosition(worm, targetLocation);

            var attackPosition  = worm.CenterPosition;
            var affectedPlayers = lunch.Select(x => x.Owner).Distinct().ToList();

            PlayAttack(worm, attackPosition, affectedPlayers);
            foreach (var notify in worm.TraitsImplementing <INotifyAttack>())
            {
                notify.Attacking(worm, target, null, null);
            }

            return(true);
        }
예제 #4
0
        public override Activity Tick(Actor self)
        {
            if (ticks == 0 && IsCanceled)
            {
                return(NextActivity);
            }

            mobile.SetVisualPosition(self, WPos.LerpQuadratic(from, to, angle, ++ticks, length));
            if (ticks >= length)
            {
                mobile.SetLocation(mobile.ToCell, mobile.ToSubCell, mobile.ToCell, mobile.ToSubCell);
                mobile.FinishedMoving(self);
                mobile.IsMoving = false;

                self.World.ActorMap.GetActorsAt(mobile.ToCell, mobile.ToSubCell)
                .Except(new[] { self }).Where(t => weapon.IsValidAgainst(t, self))
                .Do(t => t.Kill(self, damageTypes));

                return(NextActivity);
            }

            return(this);
        }
예제 #5
0
        public override bool Tick(Actor self)
        {
            switch (stance)
            {
            case AttackState.Uninitialized:
                stance         = AttackState.Burrowed;
                countdown      = swallow.Info.AttackDelay;
                burrowLocation = self.Location;
                if (conditionManager != null && attackingToken == ConditionManager.InvalidConditionToken &&
                    !string.IsNullOrEmpty(swallow.Info.AttackingCondition))
                {
                    attackingToken = conditionManager.GrantCondition(self, swallow.Info.AttackingCondition);
                }
                break;

            case AttackState.Burrowed:
                if (--countdown > 0)
                {
                    return(false);
                }

                var targetLocation = target.Actor.Location;

                // The target has moved too far away
                if ((burrowLocation - targetLocation).Length > NearEnough)
                {
                    RevokeCondition(self);
                    return(true);
                }

                // The target reached solid ground
                if (!positionable.CanEnterCell(targetLocation, null, false))
                {
                    RevokeCondition(self);
                    return(true);
                }

                var targets = self.World.ActorMap.GetActorsAt(targetLocation)
                              .Where(t => !t.Equals(self) && weapon.IsValidAgainst(t, self));

                if (!targets.Any())
                {
                    RevokeCondition(self);
                    return(true);
                }

                stance               = AttackState.Attacking;
                countdown            = swallow.Info.ReturnDelay;
                sandworm.IsAttacking = true;
                AttackTargets(self, targets);

                break;

            case AttackState.Attacking:
                if (--countdown > 0)
                {
                    return(false);
                }

                sandworm.IsAttacking = false;

                // There is a chance that the worm would just go away after attacking
                if (self.World.SharedRandom.Next(100) <= sandworm.WormInfo.ChanceToDisappear)
                {
                    self.CancelActivity();
                    self.World.AddFrameEndTask(w => self.Dispose());
                }

                RevokeCondition(self);
                return(true);
            }

            return(false);
        }
예제 #6
0
        // 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);
        }
예제 #7
0
        // 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);
        }
예제 #8
0
        // Note: facing is only used by the legacy positioning code
        // The world coordinate model uses Actor.Orientation
        public void CheckFire(Actor self, AttackBase attack, IFacing facing, Target target)
        {
            if (FireDelay > 0)
            {
                return;
            }

            var limitedAmmo = self.TraitOrDefault <LimitedAmmo>();

            if (limitedAmmo != null && !limitedAmmo.HasAmmo())
            {
                return;
            }

            // TODO: Define weapon ranges as WRange
            var range    = new WRange((int)(1024 * Weapon.Range));
            var minRange = new WRange((int)(1024 * Weapon.MinRange));

            if (!target.IsInRange(self.CenterPosition, range))
            {
                return;
            }

            if (minRange != WRange.Zero && target.IsInRange(self.CenterPosition, minRange))
            {
                return;
            }

            if (!Weapon.IsValidAgainst(target, self.World))
            {
                return;
            }

            var barrel         = Barrels[Burst % Barrels.Length];
            var muzzlePosition = self.CenterPosition + MuzzleOffset(self, barrel);
            var legacyFacing   = MuzzleOrientation(self, barrel).Yaw.Angle / 4;

            var args = new ProjectileArgs
            {
                Weapon            = Weapon,
                Facing            = legacyFacing,
                FirepowerModifier = self.TraitsImplementing <IFirepowerModifier>()
                                    .Select(a => a.GetFirepowerModifier())
                                    .Product(),

                Source        = muzzlePosition,
                SourceActor   = self,
                PassiveTarget = target.CenterPosition,
                GuidedTarget  = target
            };

            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), 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
            {
                FireDelay = Weapon.ROF;
                Burst     = Weapon.Burst;
            }
        }