diff --git a/OpenRA.Mods.RA/Attack/AttackWander.cs b/OpenRA.Mods.RA/Attack/AttackWander.cs index b3d9ccc28b..1c586fdf69 100644 --- a/OpenRA.Mods.RA/Attack/AttackWander.cs +++ b/OpenRA.Mods.RA/Attack/AttackWander.cs @@ -8,56 +8,30 @@ */ #endregion -using OpenRA.Activities; using OpenRA.Traits; namespace OpenRA.Mods.RA.Traits { [Desc("Will AttackMove to a random location within MoveRadius when idle.", "This conflicts with player orders and should only be added to animal creeps.")] - class AttackWanderInfo : ITraitInfo, Requires + class AttackWanderInfo : WandersInfo, Requires { - public readonly int WanderMoveRadius = 10; - - [Desc("Number of ticks to wait until decreasing the effective move radius.")] - public readonly int MoveReductionRadiusScale = 5; - - public object Create(ActorInitializer init) { return new AttackWander(init.self, this); } + public override object Create(ActorInitializer init) { return new AttackWander(init.self, this); } } - class AttackWander : INotifyIdle + class AttackWander : Wanders { readonly AttackMove attackMove; - readonly AttackWanderInfo info; - - int ticksIdle; - int effectiveMoveRadius; public AttackWander(Actor self, AttackWanderInfo info) + : base(self, info) { - this.info = info; - effectiveMoveRadius = info.WanderMoveRadius; attackMove = self.TraitOrDefault(); } - public void TickIdle(Actor self) + public override void DoAction(Actor self, CPos targetPos) { - var target = self.CenterPosition + new WVec(0, -1024 * effectiveMoveRadius, 0).Rotate(WRot.FromFacing(self.World.SharedRandom.Next(255))); - var targetCell = self.World.Map.CellContaining(target); - - if (!self.World.Map.Contains(targetCell)) - { - // If MoveRadius is too big there might not be a valid cell to order the attack to (if actor is on a small island and can't leave) - if (++ticksIdle % info.MoveReductionRadiusScale == 0) - effectiveMoveRadius--; - - return; // We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop - } - - attackMove.ResolveOrder(self, new Order("AttackMove", self, false) { TargetLocation = targetCell }); - - ticksIdle = 0; - effectiveMoveRadius = info.WanderMoveRadius; + attackMove.ResolveOrder(self, new Order("AttackMove", self, false) { TargetLocation = targetPos }); } } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index dd600f772f..22fcc3ad43 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -79,6 +79,7 @@ + diff --git a/OpenRA.Mods.RA/Traits/Wanders.cs b/OpenRA.Mods.RA/Traits/Wanders.cs new file mode 100644 index 0000000000..168ce9a3ce --- /dev/null +++ b/OpenRA.Mods.RA/Traits/Wanders.cs @@ -0,0 +1,79 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Traits; + +namespace OpenRA.Mods.RA.Traits +{ + [Desc("Wanders around aimlesly when idle.")] + abstract class WandersInfo : ITraitInfo + { + public readonly int WanderMoveRadius = 10; + + [Desc("Number of ticks to wait until decreasing the effective move radius.")] + public readonly int MoveReductionRadiusScale = 5; + + public abstract object Create(ActorInitializer init); + } + + class Wanders : INotifyAddedToWorld, INotifyBecomingIdle + { + readonly Actor self; + readonly WandersInfo info; + + int ticksIdle; + int effectiveMoveRadius; + + public Wanders(Actor self, WandersInfo info) + { + this.self = self; + this.info = info; + effectiveMoveRadius = info.WanderMoveRadius; + } + + public void AddedToWorld(Actor self) + { + OnBecomingIdle(self); + } + + public void OnBecomingIdle(Actor self) + { + var targetPos = PickTargetLocation(); + if (targetPos != CPos.Zero) + DoAction(self, targetPos); + } + + CPos PickTargetLocation() + { + var target = self.CenterPosition + new WVec(0, -1024 * effectiveMoveRadius, 0).Rotate(WRot.FromFacing(self.World.SharedRandom.Next(255))); + var targetCell = self.World.Map.CellContaining(target); + + if (!self.World.Map.Contains(targetCell)) + { + // If MoveRadius is too big there might not be a valid cell to order the attack to (if actor is on a small island and can't leave) + if (++ticksIdle % info.MoveReductionRadiusScale == 0) + effectiveMoveRadius--; + + return CPos.Zero; // We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop + } + + ticksIdle = 0; + effectiveMoveRadius = info.WanderMoveRadius; + + return targetCell; + } + + public virtual void DoAction(Actor self, CPos targetPos) + { + throw new NotImplementedException("Base class Wanders does not implement method DoAction!"); + } + } +}