#region Copyright & License Information /* * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, * see COPYING. */ #endregion using System; using OpenRA.Activities; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Actor will follow units until in range to attack them.")] public class AttackFollowInfo : AttackBaseInfo { public override object Create(ActorInitializer init) { return new AttackFollow(init.Self, this); } } public class AttackFollow : AttackBase, ITick, INotifyOwnerChanged { public Target Target { get; protected set; } public AttackFollow(Actor self, AttackFollowInfo info) : base(self, info) { } public virtual void Tick(Actor self) { DoAttack(self, Target); IsAttacking = Target.IsValidFor(self); } public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove) { return new AttackActivity(self, newTarget, allowMove); } public override void ResolveOrder(Actor self, Order order) { base.ResolveOrder(self, order); if (order.OrderString == "Stop") Target = Target.Invalid; } public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) { Target = Target.Invalid; } class AttackActivity : Activity { readonly AttackFollow attack; readonly IMove move; readonly Target target; public AttackActivity(Actor self, Target target, bool allowMove) { attack = self.Trait(); move = allowMove ? self.TraitOrDefault() : null; // HACK: Mobile.OnRails is horrible var mobile = move as Mobile; if (mobile != null && mobile.Info.OnRails) move = null; this.target = target; } public override Activity Tick(Actor self) { if (IsCanceled || !target.IsValidFor(self)) return NextActivity; if (self.IsDisabled()) return this; var weapon = attack.ChooseArmamentForTarget(target); if (weapon != null) { var targetIsMobile = (target.Type == TargetType.Actor && target.Actor.HasTrait()) || (target.Type == TargetType.FrozenActor && target.FrozenActor.Info.Traits.Contains()); // Try and sit at least one cell closer than the max range to give some leeway if the target starts moving. var maxRange = targetIsMobile ? new WDist(Math.Max(weapon.Weapon.MinRange.Length, weapon.Weapon.Range.Length - 1024)) : weapon.Weapon.Range; attack.Target = target; if (move != null) return Util.SequenceActivities(move.MoveFollow(self, target, weapon.Weapon.MinRange, maxRange), this); } return NextActivity; } } } }