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 Activity InnerTick(Actor self, AttackBase attack)
        {
            if (IsCanceled)
            {
                return(NextActivity);
            }

            if (!Target.IsValid)
            {
                return(NextActivity);
            }

            if (!self.Owner.HasFogVisibility() && Target.Actor != null && Target.Actor.HasTrait <Mobile>() && !self.Owner.Shroud.IsTargetable(Target.Actor))
            {
                return(NextActivity);
            }

            if (targetable != null && !targetable.TargetableBy(Target.Actor, self))
            {
                return(NextActivity);
            }

            if (!Combat.IsInRange(self.CenterLocation, Range, Target))
            {
                if (--nextPathTime > 0)
                {
                    return(this);
                }

                nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread,
                                                            delayBetweenPathingAttempts + delaySpread);

                return((AllowMovement) ? Util.SequenceActivities(self.Trait <Mobile>().MoveWithinRange(Target, Range), this) : NextActivity);
            }

            var desiredFacing = Util.GetFacing(Target.CenterLocation - self.CenterLocation, 0);
            var facing        = self.Trait <IFacing>();

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

            attack.DoAttack(self, Target);
            return(this);
        }
Example #3
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);
            }

            // TODO: This is horrible, and probably wrong. Work out what it is trying to solve, then redo it properly.
            if (type == TargetType.Actor && !self.Owner.HasFogVisibility() && Target.Actor.HasTrait <Mobile>() && !self.Owner.Shroud.IsTargetable(Target.Actor))
            {
                return(NextActivity);
            }

            if (!Target.IsInRange(self.CenterPosition, Range))
            {
                if (--nextPathTime > 0)
                {
                    return(this);
                }

                nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread,
                                                            delayBetweenPathingAttempts + delaySpread);

                return((AllowMovement) ? Util.SequenceActivities(self.Trait <Mobile>().MoveWithinRange(Target, Range), this) : NextActivity);
            }

            var desiredFacing = Util.GetFacing(Target.CenterPosition - self.CenterPosition, 0);
            var facing        = self.Trait <IFacing>();

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

            attack.DoAttack(self, Target);
            return(this);
        }
Example #4
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);
            }

            // 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 (type == TargetType.Actor && !Target.Actor.HasTrait <FrozenUnderFog>() && !self.Owner.Shroud.IsTargetable(Target.Actor))
            {
                return(NextActivity);
            }

            // 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(desiredFacing), this));
            }

            attack.DoAttack(self, Target);

            return(this);
        }
Example #5
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);
        }