Example #1
0
        protected virtual Activity InnerTick(Actor self, AttackBase attack)
        {
            if (IsCanceled)
            {
                return(NextActivity);
            }

            var type = Target.Type;

            if (!Target.IsValidFor(self) || type == TargetType.FrozenActor)
            {
                return(NextActivity);
            }

            if (attack.Info.AttackRequiresEnteringCell && !positionable.CanEnterCell(Target.Actor.Location, null, false))
            {
                return(NextActivity);
            }

            // Drop the target if it moves under the shroud / fog.
            // HACK: This would otherwise break targeting frozen actors
            // The problem is that Shroud.IsTargetable returns false (as it should) for
            // frozen actors, but we do want to explicitly target the underlying actor here.
            if (!attack.Info.IgnoresVisibility && type == TargetType.Actor && !Target.Actor.Info.HasTraitInfo <FrozenUnderFogInfo>() && !self.Owner.CanTargetActor(Target.Actor))
            {
                return(NextActivity);
            }

            // Drop the target once none of the weapons are effective against it
            var armaments = attack.ChooseArmamentsForTarget(Target, forceAttack);

            if (!armaments.Any())
            {
                return(NextActivity);
            }

            // Update ranges
            minRange = armaments.Max(a => a.Weapon.MinRange);
            maxRange = armaments.Min(a => a.MaxRange());

            // Try to move within range
            if (move != null && (!Target.IsInRange(self.CenterPosition, maxRange) || Target.IsInRange(self.CenterPosition, minRange)))
            {
                return(Util.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this));
            }

            var desiredFacing = Util.GetFacing(Target.CenterPosition - self.CenterPosition, 0);

            if (facing.Facing != desiredFacing)
            {
                return(Util.SequenceActivities(new Turn(self, desiredFacing), this));
            }

            attack.DoAttack(self, Target, armaments);

            return(this);
        }
Example #2
0
        protected virtual AttackStatus TickAttack(Actor self, AttackBase attack)
        {
            if (IsCanceled)
            {
                return(AttackStatus.UnableToAttack);
            }

            var type = Target.Type;

            if (!Target.IsValidFor(self) || type == TargetT.FrozenActor)
            {
                return(AttackStatus.UnableToAttack);
            }

            if (attack.Info.AttackRequiresEnteringCell && !positionable.CanEnterCell(Target.Actor.Location, null, false))
            {
                return(AttackStatus.UnableToAttack);
            }

            //Drop the target if it moves under the shroud / fog.
            if (!attack.Info.IgnoresVisibility && type == TargetT.Actor &&
                !Target.Actor.Info.HasTraitInfo <FrozenUnderFogInfo>() &&
                !Target.Actor.CanBeViewedByPlayer(self.Owner))
            {
                return(AttackStatus.UnableToAttack);
            }

            //Drop the target once none of the weapons are effective against it

            var armaments = attack.ChooseArmamentsForTarget(Target, forceAttack).ToList();

            if (armaments.Count == 0)
            {
                return(AttackStatus.UnableToAttack);
            }

            //Update ranges
            minRange = armaments.Max(a => a.Weapon.MinRange);
            maxRange = armaments.Min(a => a.MaxRange());

            var pos    = self.CenterPosition;
            var mobile = move as Mobile;

            if (!Target.IsInRange(pos, maxRange) ||
                (minRange.Length != 0 && Target.IsInRange(pos, minRange)) ||
                (mobile != null && !mobile.CanInteractWithGroundLayer(self)))
            {
                //Try to move within range,drop the target otherwise.
                if (move == null)
                {
                    return(AttackStatus.UnableToAttack);
                }

                attackStatus |= AttackStatus.NeedsToMove;
                moveActivity  = ActivityUtils.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this);
                return(AttackStatus.NeedsToMove);
            }

            var targetedPosition = attack.GetTargetPosition(pos, Target);
            var desiredFacing    = (targetedPosition - pos).Yaw.Facing;

            if (!Util.FacingWithinTolerance(facing.Facing, desiredFacing, facingTolerance))
            {
                attackStatus |= AttackStatus.NeedsToTurn;
                turnActivity  = ActivityUtils.SequenceActivities(new Turn(self, desiredFacing), this);
                return(AttackStatus.NeedsToTurn);
            }

            attackStatus |= AttackStatus.Attacking;
            attack.DoAttack(self, Target, armaments);

            return(AttackStatus.Attacking);
        }
        protected virtual Activity InnerTick(Actor self, AttackBase attack)
        {
            if (IsCanceled)
            {
                return(NextActivity);
            }

            var type = Target.Type;

            if (!Target.IsValidFor(self) || type == TargetType.FrozenActor)
            {
                return(NextActivity);
            }

            if (attack.Info.AttackRequiresEnteringCell && !positionable.CanEnterCell(Target.Actor.Location, null, false))
            {
                return(NextActivity);
            }

            // Drop the target if it moves under the shroud / fog.
            // HACK: This would otherwise break targeting frozen actors
            // The problem is that Shroud.IsTargetable returns false (as it should) for
            // frozen actors, but we do want to explicitly target the underlying actor here.
            if (!attack.Info.IgnoresVisibility && type == TargetType.Actor && !Target.Actor.Info.HasTraitInfo <FrozenUnderFogInfo>() && !self.Owner.CanTargetActor(Target.Actor))
            {
                return(NextActivity);
            }

            // Drop the target once none of the weapons are effective against it
            var armaments = attack.ChooseArmamentsForTarget(Target, forceAttack).ToList();

            if (armaments.Count == 0)
            {
                return(NextActivity);
            }

            // Update ranges
            minRange = armaments.Max(a => a.Weapon.MinRange);
            maxRange = armaments.Min(a => a.MaxRange());

            var pos    = self.CenterPosition;
            var mobile = move as Mobile;

            if (!Target.IsInRange(pos, maxRange) ||
                (minRange.Length != 0 && Target.IsInRange(pos, minRange)) ||
                (mobile != null && !mobile.CanInteractWithGroundLayer(self)))
            {
                // Try to move within range, drop the target otherwise
                if (move == null)
                {
                    return(NextActivity);
                }

                attackStatus |= AttackStatus.NeedsToMove;
                moveActivity  = ActivityUtils.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this);
                return(NextActivity);
            }

            var targetedPosition = attack.GetTargetPosition(pos, Target);
            var desiredFacing    = (targetedPosition - pos).Yaw.Facing;

            if (facing.Facing != desiredFacing)
            {
                attackStatus |= AttackStatus.NeedsToTurn;
                turnActivity  = ActivityUtils.SequenceActivities(new Turn(self, desiredFacing), this);
                return(NextActivity);
            }

            attackStatus |= AttackStatus.Attacking;
            attack.DoAttack(self, Target, armaments);

            return(this);
        }