diff --git a/OpenRA.Game/Sound.cs b/OpenRA.Game/Sound.cs index 6760ff7c7b..78281f8d22 100644 --- a/OpenRA.Game/Sound.cs +++ b/OpenRA.Game/Sound.cs @@ -79,7 +79,7 @@ namespace OpenRA public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); } - static ISound Play(Player player, string name, bool headRelative, PPos pos, float volumeModifier) + static ISound Play(Player player, string name, bool headRelative, WPos pos, float volumeModifier) { if (String.IsNullOrEmpty(name)) return null; @@ -87,16 +87,16 @@ namespace OpenRA return null; return soundEngine.Play2D(sounds[name], - false, headRelative, pos.ToFloat2(), + false, headRelative, PPos.FromWPosHackZ(pos).ToFloat2(), InternalSoundVolume * volumeModifier, true); } - public static ISound Play(string name) { return Play(null, name, true, PPos.Zero, 1); } - public static ISound Play(string name, PPos pos) { return Play(null, name, false, pos, 1); } - public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, PPos.Zero, volumeModifier); } - public static ISound Play(string name, PPos pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); } - public static ISound PlayToPlayer(Player player, string name) { return Play(player, name, true, PPos.Zero, 1); } - public static ISound PlayToPlayer(Player player, string name, PPos pos) { return Play(player, name, false, pos, 1); } + public static ISound Play(string name) { return Play(null, name, true, WPos.Zero, 1); } + public static ISound Play(string name, WPos pos) { return Play(null, name, false, pos, 1); } + public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, WPos.Zero, volumeModifier); } + public static ISound Play(string name, WPos pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); } + public static ISound PlayToPlayer(Player player, string name) { return Play(player, name, true, WPos.Zero, 1); } + public static ISound PlayToPlayer(Player player, string name, WPos pos) { return Play(player, name, false, pos, 1); } public static void PlayVideo(byte[] raw) { diff --git a/OpenRA.Game/Traits/Target.cs b/OpenRA.Game/Traits/Target.cs index 04664d7c07..2bd84ffd11 100644 --- a/OpenRA.Game/Traits/Target.cs +++ b/OpenRA.Game/Traits/Target.cs @@ -80,7 +80,7 @@ namespace OpenRA.Traits if (targetable == null) return new []{actor.CenterPosition}; - return targetable.TargetableCells(actor).Select(c => c.CenterPosition); + return targetable.TargetablePositions(actor); } } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index c857a32a33..8bcda46358 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -201,7 +201,7 @@ namespace OpenRA.Traits public interface ITargetable { string[] TargetTypes { get; } - IEnumerable TargetableCells(Actor self); + IEnumerable TargetablePositions(Actor self); bool TargetableBy(Actor self, Actor byActor); } diff --git a/OpenRA.Mods.Cnc/IonCannonPower.cs b/OpenRA.Mods.Cnc/IonCannonPower.cs index 03b0eee3b9..3a96806c10 100644 --- a/OpenRA.Mods.Cnc/IonCannonPower.cs +++ b/OpenRA.Mods.Cnc/IonCannonPower.cs @@ -32,7 +32,7 @@ namespace OpenRA.Mods.Cnc { self.World.AddFrameEndTask(w => { - Sound.Play(Info.LaunchSound, order.TargetLocation.ToPPos()); + Sound.Play(Info.LaunchSound, order.TargetLocation.CenterPosition); w.Add(new IonCannon(self, w, order.TargetLocation)); }); } diff --git a/OpenRA.Mods.RA/AI/HackyAI.cs b/OpenRA.Mods.RA/AI/HackyAI.cs index b864e199b0..d6407cdf84 100644 --- a/OpenRA.Mods.RA/AI/HackyAI.cs +++ b/OpenRA.Mods.RA/AI/HackyAI.cs @@ -226,18 +226,18 @@ namespace OpenRA.Mods.RA.AI protected static bool CanAttackTarget(Actor a, Actor target) { - if (!a.HasTrait()) return false; - if (!target.HasTrait>() && - !target.HasTrait()) return false; + if (!a.HasTrait()) + return false; + + var targetable = target.TraitOrDefault(); + if (targetable == null) + return false; var arms = a.TraitsImplementing(); foreach (var arm in arms) - if (target.HasTrait>() && - arm.Weapon.ValidTargets.Intersect(target.Trait>().TargetTypes) != null) - return true; - else if (target.HasTrait() && - arm.Weapon.ValidTargets.Intersect(target.Trait().TargetTypes) != null) + if (arm.Weapon.ValidTargets.Intersect(targetable.TargetTypes) != null) return true; + return false; } } diff --git a/OpenRA.Mods.RA/Activities/Attack.cs b/OpenRA.Mods.RA/Activities/Attack.cs index 28d00a3b68..c583115ed8 100755 --- a/OpenRA.Mods.RA/Activities/Attack.cs +++ b/OpenRA.Mods.RA/Activities/Attack.cs @@ -70,7 +70,7 @@ namespace OpenRA.Mods.RA.Activities nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, delayBetweenPathingAttempts + delaySpread); - return (AllowMovement) ? Util.SequenceActivities(self.Trait().MoveWithinRange(Target, Range.Range / 1024), this) : NextActivity; + return (AllowMovement) ? Util.SequenceActivities(self.Trait().MoveWithinRange(Target, Range), this) : NextActivity; } var desiredFacing = Util.GetFacing(Target.CenterPosition - self.CenterPosition, 0); diff --git a/OpenRA.Mods.RA/Activities/Follow.cs b/OpenRA.Mods.RA/Activities/Follow.cs index 8e5bae7cd7..70827aeb6b 100644 --- a/OpenRA.Mods.RA/Activities/Follow.cs +++ b/OpenRA.Mods.RA/Activities/Follow.cs @@ -15,34 +15,32 @@ namespace OpenRA.Mods.RA.Activities { public class Follow : Activity { - Target Target; - int Range; + Target target; + WRange range; int nextPathTime; const int delayBetweenPathingAttempts = 20; const int delaySpread = 5; - public Follow(Target target, int range) + public Follow(Target target, WRange range) { - Target = target; - Range = range; + this.target = target; + this.range = range; } - public override Activity Tick( Actor self ) + public override Activity Tick(Actor self) { - if (IsCanceled) return NextActivity; - if (!Target.IsValid) return NextActivity; + if (IsCanceled || !target.IsValid) + return NextActivity; - var inRange = ( Target.CenterPosition.ToCPos() - self.Location ).LengthSquared < Range * Range; - - if( inRange ) return this; - if (--nextPathTime > 0) return this; + if (target.IsInRange(self.CenterPosition, range) || --nextPathTime > 0) + return this; nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, delayBetweenPathingAttempts + delaySpread); var mobile = self.Trait(); - return Util.SequenceActivities( mobile.MoveWithinRange( Target, Range ), this ); + return Util.SequenceActivities(mobile.MoveWithinRange(target, range), this); } } } diff --git a/OpenRA.Mods.RA/Activities/Leap.cs b/OpenRA.Mods.RA/Activities/Leap.cs index 289e87e379..7be3de70d2 100644 --- a/OpenRA.Mods.RA/Activities/Leap.cs +++ b/OpenRA.Mods.RA/Activities/Leap.cs @@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA.Activities self.Trait().Attacking(self, Target.FromActor(target)); if (weapon.Report != null && weapon.Report.Any()) - Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterLocation); + Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterPosition); } public override Activity Tick(Actor self) diff --git a/OpenRA.Mods.RA/Activities/MakeAnimation.cs b/OpenRA.Mods.RA/Activities/MakeAnimation.cs index 1eb0c0bd18..8444f34f8e 100644 --- a/OpenRA.Mods.RA/Activities/MakeAnimation.cs +++ b/OpenRA.Mods.RA/Activities/MakeAnimation.cs @@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA.Activities var bi = self.Info.Traits.GetOrDefault(); if (bi != null) foreach (var s in bi.SellSounds) - Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); + Sound.PlayToPlayer(self.Owner, s, self.CenterPosition); rb.PlayCustomAnimBackwards(self, "make", () => { OnComplete(); complete = true;}); } diff --git a/OpenRA.Mods.RA/Activities/Teleport.cs b/OpenRA.Mods.RA/Activities/Teleport.cs index f9809d9f83..cd54a55119 100755 --- a/OpenRA.Mods.RA/Activities/Teleport.cs +++ b/OpenRA.Mods.RA/Activities/Teleport.cs @@ -29,8 +29,8 @@ namespace OpenRA.Mods.RA.Activities public override Activity Tick(Actor self) { - Sound.Play("chrono2.aud", self.Location.ToPPos()); - Sound.Play("chrono2.aud", destination.ToPPos()); + Sound.Play("chrono2.aud", self.CenterPosition); + Sound.Play("chrono2.aud", destination.CenterPosition); self.Trait().SetPosition(self, destination); self.Generation++; diff --git a/OpenRA.Mods.RA/Activities/Transform.cs b/OpenRA.Mods.RA/Activities/Transform.cs index be5cee0329..77d9656bff 100644 --- a/OpenRA.Mods.RA/Activities/Transform.cs +++ b/OpenRA.Mods.RA/Activities/Transform.cs @@ -44,7 +44,7 @@ namespace OpenRA.Mods.RA.Activities self.Destroy(); foreach (var s in Sounds) - Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); + Sound.PlayToPlayer(self.Owner, s, self.CenterPosition); var init = new TypeDictionary { diff --git a/OpenRA.Mods.RA/Air/EjectOnDeath.cs b/OpenRA.Mods.RA/Air/EjectOnDeath.cs index d3824b9c2b..74cf19de12 100644 --- a/OpenRA.Mods.RA/Air/EjectOnDeath.cs +++ b/OpenRA.Mods.RA/Air/EjectOnDeath.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA && self.Owner.WinState != WinState.Lost) { self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot, self.CenterPosition))); - Sound.Play(info.ChuteSound, self.CenterLocation); + Sound.Play(info.ChuteSound, self.CenterPosition); } else pilot.Destroy(); diff --git a/OpenRA.Mods.RA/Air/TargetableAircraft.cs b/OpenRA.Mods.RA/Air/TargetableAircraft.cs index 9dff2197fe..49bcd2ffd8 100755 --- a/OpenRA.Mods.RA/Air/TargetableAircraft.cs +++ b/OpenRA.Mods.RA/Air/TargetableAircraft.cs @@ -21,12 +21,15 @@ namespace OpenRA.Mods.RA.Air public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); } } - public class TargetableAircraft : TargetableUnit + public class TargetableAircraft : TargetableUnit { - Aircraft Aircraft; + readonly TargetableAircraftInfo info; + readonly Aircraft Aircraft; + public TargetableAircraft(Actor self, TargetableAircraftInfo info) : base(self, info) { + this.info = info; Aircraft = self.Trait(); } diff --git a/OpenRA.Mods.RA/Armament.cs b/OpenRA.Mods.RA/Armament.cs index 7ec683ac00..e1b09e3e79 100755 --- a/OpenRA.Mods.RA/Armament.cs +++ b/OpenRA.Mods.RA/Armament.cs @@ -154,7 +154,7 @@ namespace OpenRA.Mods.RA self.World.Add(projectile); if (args.weapon.Report != null && args.weapon.Report.Any()) - Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterLocation); + Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterPosition); } }); diff --git a/OpenRA.Mods.RA/Attack/AttackFrontal.cs b/OpenRA.Mods.RA/Attack/AttackFrontal.cs index 4e5abbb442..47c67ef1b0 100644 --- a/OpenRA.Mods.RA/Attack/AttackFrontal.cs +++ b/OpenRA.Mods.RA/Attack/AttackFrontal.cs @@ -19,14 +19,18 @@ namespace OpenRA.Mods.RA { public readonly int FacingTolerance = 1; - public override object Create( ActorInitializer init ) { return new AttackFrontal( init.self, this ); } + public override object Create(ActorInitializer init) { return new AttackFrontal(init.self, this); } } public class AttackFrontal : AttackBase { readonly AttackFrontalInfo info; + public AttackFrontal(Actor self, AttackFrontalInfo info) - : base( self ) { this.info = info; } + : base(self) + { + this.info = info; + } protected override bool CanAttack(Actor self, Target target) { diff --git a/OpenRA.Mods.RA/Attack/AttackTurreted.cs b/OpenRA.Mods.RA/Attack/AttackTurreted.cs index 24d35c868d..06c944ce44 100644 --- a/OpenRA.Mods.RA/Attack/AttackTurreted.cs +++ b/OpenRA.Mods.RA/Attack/AttackTurreted.cs @@ -95,12 +95,11 @@ namespace OpenRA.Mods.RA if (weapon != null) { - attack.target = target; + var range = WRange.FromCells(Math.Max(0, (int)weapon.Weapon.Range - RangeTolerance)); + attack.target = target; if (allowMove && self.HasTrait() && !self.Info.Traits.Get().OnRails) - return Util.SequenceActivities( - new Follow( target, Math.Max( 0, (int)weapon.Weapon.Range - RangeTolerance ) ), - this ); + return Util.SequenceActivities(new Follow(target, range), this); } return NextActivity; diff --git a/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs b/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs index e9e3762538..dd7acc987b 100644 --- a/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs +++ b/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs @@ -32,9 +32,9 @@ namespace OpenRA.Mods.RA.Buildings public void DamageStateChanged(Actor self, AttackInfo e) { if (e.DamageState == DamageState.Dead) - Sound.Play(Info.DestroyedSound, self.CenterLocation); + Sound.Play(Info.DestroyedSound, self.CenterPosition); else if (e.DamageState >= DamageState.Heavy && e.PreviousDamageState < DamageState.Heavy) - Sound.Play(Info.DamagedSound, self.CenterLocation); + Sound.Play(Info.DamagedSound, self.CenterPosition); } } } diff --git a/OpenRA.Mods.RA/Buildings/Wall.cs b/OpenRA.Mods.RA/Buildings/Wall.cs index 727aa0bd59..7213ce6946 100755 --- a/OpenRA.Mods.RA/Buildings/Wall.cs +++ b/OpenRA.Mods.RA/Buildings/Wall.cs @@ -44,7 +44,7 @@ namespace OpenRA.Mods.RA.Buildings public void OnCrush(Actor crusher) { self.Kill(crusher); - Sound.Play(info.CrushSound, self.CenterLocation); + Sound.Play(info.CrushSound, self.CenterPosition); } } } diff --git a/OpenRA.Mods.RA/CarpetBomb.cs b/OpenRA.Mods.RA/CarpetBomb.cs index 03e612d3fe..80148646a6 100644 --- a/OpenRA.Mods.RA/CarpetBomb.cs +++ b/OpenRA.Mods.RA/CarpetBomb.cs @@ -70,7 +70,7 @@ namespace OpenRA.Mods.RA self.World.Add(args.weapon.Projectile.Create(args)); if (args.weapon.Report != null && args.weapon.Report.Any()) - Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterLocation); + Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterPosition); } } } diff --git a/OpenRA.Mods.RA/Cloak.cs b/OpenRA.Mods.RA/Cloak.cs index 81fa26ede3..aef6315148 100644 --- a/OpenRA.Mods.RA/Cloak.cs +++ b/OpenRA.Mods.RA/Cloak.cs @@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA public void Uncloak(int time) { if (Cloaked) - Sound.Play(info.UncloakSound, self.CenterLocation); + Sound.Play(info.UncloakSound, self.CenterPosition); remainingTime = Math.Max(remainingTime, time); } @@ -86,7 +86,7 @@ namespace OpenRA.Mods.RA { if (remainingTime > 0 && canCloak) if (--remainingTime <= 0) - Sound.Play(info.CloakSound, self.CenterLocation); + Sound.Play(info.CloakSound, self.CenterPosition); if (self.IsDisabled()) Uncloak(); diff --git a/OpenRA.Mods.RA/Combat.cs b/OpenRA.Mods.RA/Combat.cs index c65c21837a..956badf6b0 100755 --- a/OpenRA.Mods.RA/Combat.cs +++ b/OpenRA.Mods.RA/Combat.cs @@ -43,11 +43,12 @@ namespace OpenRA.Mods.RA var isWater = args.destAltitude == 0 && world.GetTerrainInfo(targetTile).IsWater; var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion; + var dest = args.dest.ToWPos(args.destAltitude); if (explosionType != null) world.AddFrameEndTask( - w => w.Add(new Explosion(w, args.dest.ToWPos(args.destAltitude), explosionType))); + w => w.Add(new Explosion(w, dest, explosionType))); - Sound.Play(GetImpactSound(warhead, isWater), args.dest); + Sound.Play(GetImpactSound(warhead, isWater), dest); var smudgeLayers = world.WorldActor.TraitsImplementing().ToDictionary(x => x.Info.Type); @@ -156,7 +157,7 @@ namespace OpenRA.Mods.RA }; if (args.weapon.Report != null && args.weapon.Report.Any()) - Sound.Play(args.weapon.Report.Random(attacker.World.SharedRandom), pxPos); + Sound.Play(args.weapon.Report.Random(attacker.World.SharedRandom), pos); DoImpacts(args); } diff --git a/OpenRA.Mods.RA/Crates/CloakCrateAction.cs b/OpenRA.Mods.RA/Crates/CloakCrateAction.cs index bf6702200f..e7b7498685 100644 --- a/OpenRA.Mods.RA/Crates/CloakCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/CloakCrateAction.cs @@ -52,7 +52,7 @@ namespace OpenRA.Mods.RA.Crates w.Remove(collector); collector.AddTrait(cloak); - var t = collector.TraitOrDefault>(); + var t = collector.TraitOrDefault(); if (t != null) t.ReceivedCloak(collector); w.Add(collector); diff --git a/OpenRA.Mods.RA/CrushableInfantry.cs b/OpenRA.Mods.RA/CrushableInfantry.cs index 3b625c056f..c5f9c1f167 100644 --- a/OpenRA.Mods.RA/CrushableInfantry.cs +++ b/OpenRA.Mods.RA/CrushableInfantry.cs @@ -47,7 +47,7 @@ namespace OpenRA.Mods.RA public void OnCrush(Actor crusher) { - Sound.Play(Info.CrushSound, crusher.CenterLocation); + Sound.Play(Info.CrushSound, crusher.CenterPosition); ri.SpawnCorpse(self, Info.CorpseSequence); self.Kill(crusher); } diff --git a/OpenRA.Mods.RA/Guard.cs b/OpenRA.Mods.RA/Guard.cs index 12efeca889..355976d44b 100644 --- a/OpenRA.Mods.RA/Guard.cs +++ b/OpenRA.Mods.RA/Guard.cs @@ -28,8 +28,10 @@ namespace OpenRA.Mods.RA { var target = Target.FromActor(order.TargetActor); self.SetTargetLine(target, Color.Yellow); + + var range = WRange.FromCells(target.Actor.Info.Traits.Get().Range); self.QueueActivity(false, new AttackMove.AttackMoveActivity(self, - new Follow(target, target.Actor.Info.Traits.Get().Range))); + new Follow(target, range))); } } diff --git a/OpenRA.Mods.RA/Missions/Allies01Script.cs b/OpenRA.Mods.RA/Missions/Allies01Script.cs index 87c3866f83..1ac6863e15 100644 --- a/OpenRA.Mods.RA/Missions/Allies01Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies01Script.cs @@ -191,14 +191,14 @@ namespace OpenRA.Mods.RA.Missions if (einstein != null) { if (einstein.IsInWorld) - innerActivity = new Move.Move(Target.FromActor(einstein), 3); + innerActivity = new Move.Move(Target.FromActor(einstein), WRange.FromCells(3)); else { var container = world.UnitContaining(einstein); if (container != null && !container.HasTrait() && container.HasTrait()) - innerActivity = new Move.Move(Target.FromActor(container), 3); + innerActivity = new Move.Move(Target.FromActor(container), WRange.FromCells(3)); else innerActivity = new Move.Move(extractionLZ.Location, 3); diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index f109367585..df97bc8c3d 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -516,7 +516,7 @@ namespace OpenRA.Mods.RA.Move public Activity ScriptedMove(CPos cell) { return new Move(cell); } public Activity MoveTo(CPos cell, int nearEnough) { return new Move(cell, nearEnough); } public Activity MoveTo(CPos cell, Actor ignoredActor) { return new Move(cell, ignoredActor); } - public Activity MoveWithinRange(Target target, int range) { return new Move(target, range); } + public Activity MoveWithinRange(Target target, WRange range) { return new Move(target, range); } public Activity MoveTo(Func> pathFunc) { return new Move(pathFunc); } } } diff --git a/OpenRA.Mods.RA/Move/Move.cs b/OpenRA.Mods.RA/Move/Move.cs index 5e5cec526b..b0a527c1ec 100755 --- a/OpenRA.Mods.RA/Move/Move.cs +++ b/OpenRA.Mods.RA/Move/Move.cs @@ -21,11 +21,16 @@ namespace OpenRA.Mods.RA.Move class Move : Activity { CPos? destination; - int nearEnough; + WRange nearEnough; public List path; Func> getPath; public Actor ignoreBuilding; + // For dealing with blockers + bool hasWaited; + bool hasNotifiedBlocker; + int waitTicksRemaining; + // Scriptable move order // Ignores lane bias and nearby units public Move(CPos destination) @@ -35,10 +40,14 @@ namespace OpenRA.Mods.RA.Move PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, destination, false ) .WithoutLaneBias()); this.destination = destination; - this.nearEnough = 0; + this.nearEnough = WRange.Zero; } + // Hack for legacy code public Move(CPos destination, int nearEnough) + : this(destination, WRange.FromCells(nearEnough)) {} + + public Move(CPos destination, WRange nearEnough) { this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindUnitPath( mobile.toCell, destination, self ); this.destination = destination; @@ -54,12 +63,12 @@ namespace OpenRA.Mods.RA.Move ); this.destination = destination; - this.nearEnough = 0; + this.nearEnough = WRange.Zero; this.ignoreBuilding = ignoreBuilding; } static readonly List NoPath = new List(); - public Move(Target target, int range) + public Move(Target target, WRange range) { this.getPath = (self, mobile) => { @@ -67,7 +76,7 @@ namespace OpenRA.Mods.RA.Move return NoPath; return self.World.WorldActor.Trait().FindUnitPathToRange( - mobile.toCell, target.CenterPosition.ToCPos(), range, self); + mobile.toCell, mobile.toSubCell, target.CenterPosition, range, self); }; this.destination = null; @@ -78,7 +87,7 @@ namespace OpenRA.Mods.RA.Move { this.getPath = (_1,_2) => getPath(); this.destination = null; - this.nearEnough = 0; + this.nearEnough = WRange.Zero; } static int HashList(List xs) @@ -95,12 +104,10 @@ namespace OpenRA.Mods.RA.Move { var path = getPath(self, mobile).TakeWhile(a => a != mobile.toCell).ToList(); mobile.PathHash = HashList(path); - Log.Write("debug", "EvalPathHash #{0} {1}", - self.ActorID, mobile.PathHash); return path; } - public override Activity Tick( Actor self ) + public override Activity Tick(Actor self) { var mobile = self.Trait(); var info = self.Info.Traits.Get(); @@ -109,13 +116,14 @@ namespace OpenRA.Mods.RA.Move { if (mobile.Altitude < info.Altitude) ++mobile.Altitude; + return this; } if (destination == mobile.toCell) return NextActivity; - if( path == null ) + if (path == null) { if (mobile.ticksBeforePathing > 0) { @@ -127,54 +135,51 @@ namespace OpenRA.Mods.RA.Move SanityCheckPath( mobile ); } - if( path.Count == 0 ) + if (path.Count == 0) { destination = mobile.toCell; return this; } - destination = path[ 0 ]; + destination = path[0]; - var nextCell = PopPath( self, mobile ); - if( nextCell == null ) + var nextCell = PopPath(self, mobile); + if (nextCell == null) return this; var dir = nextCell.Value.First - mobile.fromCell; - var firstFacing = Util.GetFacing( dir, mobile.Facing ); - if( firstFacing != mobile.Facing ) + var firstFacing = Util.GetFacing(dir, mobile.Facing); + if (firstFacing != mobile.Facing) { path.Add( nextCell.Value.First ); - return Util.SequenceActivities( new Turn( firstFacing ), this ); + return Util.SequenceActivities(new Turn(firstFacing), this); } else { - mobile.SetLocation( mobile.fromCell, mobile.fromSubCell, nextCell.Value.First, nextCell.Value.Second ); + mobile.SetLocation(mobile.fromCell, mobile.fromSubCell, nextCell.Value.First, nextCell.Value.Second); var move = new MoveFirstHalf( this, - Util.CenterOfCell( mobile.fromCell ) + MobileInfo.SubCellOffsets[mobile.fromSubCell], - Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (MobileInfo.SubCellOffsets[mobile.fromSubCell] + MobileInfo.SubCellOffsets[mobile.toSubCell] ) / 2, + Util.CenterOfCell(mobile.fromCell) + MobileInfo.SubCellOffsets[mobile.fromSubCell], + Util.BetweenCells(mobile.fromCell, mobile.toCell) + (MobileInfo.SubCellOffsets[mobile.fromSubCell] + MobileInfo.SubCellOffsets[mobile.toSubCell]) / 2, mobile.Facing, mobile.Facing, - 0 ); + 0 + ); return move; } } - [Conditional( "SANITY_CHECKS")] - void SanityCheckPath( Mobile mobile ) + [Conditional("SANITY_CHECKS")] + void SanityCheckPath(Mobile mobile) { - if( path.Count == 0 ) + if (path.Count == 0) return; - var d = path[path.Count-1] - mobile.toCell; - if( d.LengthSquared > 2 ) - throw new InvalidOperationException( "(Move) Sanity check failed" ); + var d = path[path.Count - 1] - mobile.toCell; + if (d.LengthSquared > 2) + throw new InvalidOperationException("(Move) Sanity check failed"); } - bool hasWaited; - bool hasNotifiedBlocker; - int waitTicksRemaining; - void NotifyBlocker(Actor self, CPos nextCell) { foreach (var blocker in self.World.ActorMap.GetUnitsAt(nextCell)) @@ -191,22 +196,30 @@ namespace OpenRA.Mods.RA.Move Pair? PopPath(Actor self, Mobile mobile) { - if( path.Count == 0 ) return null; - var nextCell = path[ path.Count - 1 ]; - if( !mobile.CanEnterCell( nextCell, ignoreBuilding, true ) ) + if (path.Count == 0) + return null; + + var nextCell = path[path.Count - 1]; + + // Next cell in the move is blocked by another actor + if (!mobile.CanEnterCell(nextCell, ignoreBuilding, true)) { - if( ( mobile.toCell - destination.Value ).LengthSquared <= nearEnough ) + // Are we close enough? + var cellRange = nearEnough.Range / 1024; + if ((mobile.toCell - destination.Value).LengthSquared <= cellRange*cellRange) { path.Clear(); return null; } + // See if they will move if (!hasNotifiedBlocker) { NotifyBlocker(self, nextCell); hasNotifiedBlocker = true; } + // Wait a bit to see if they leave if (!hasWaited) { var info = self.Info.Traits.Get(); @@ -223,6 +236,7 @@ namespace OpenRA.Mods.RA.Move return null; } + // Calculate a new path mobile.RemoveInfluence(); var newPath = EvalPath(self, mobile); mobile.AddInfluence(); @@ -232,9 +246,10 @@ namespace OpenRA.Mods.RA.Move return null; } + hasNotifiedBlocker = false; hasWaited = false; - path.RemoveAt( path.Count - 1 ); + path.RemoveAt(path.Count - 1); var subCell = mobile.GetDesiredSubcell(nextCell, ignoreBuilding); return Pair.New(nextCell, subCell); @@ -246,11 +261,11 @@ namespace OpenRA.Mods.RA.Move base.Cancel(self); } - public override IEnumerable GetTargets( Actor self ) + public override IEnumerable GetTargets(Actor self) { - if( path != null ) - return Enumerable.Reverse(path).Select( c => Target.FromCell(c) ); - if( destination != null ) + if (path != null) + return Enumerable.Reverse(path).Select(c => Target.FromCell(c)); + if (destination != null) return new Target[] { Target.FromCell(destination.Value) }; return Target.NoTargets; } @@ -271,59 +286,59 @@ namespace OpenRA.Mods.RA.Move this.fromFacing = fromFacing; this.toFacing = toFacing; this.moveFraction = startingFraction; - this.moveFractionTotal = ( ( to - from ) * 3 ).Length; + this.moveFractionTotal = 3*(to - from).Length; } - public override void Cancel( Actor self ) + public override void Cancel(Actor self) { - move.Cancel( self ); - base.Cancel( self ); + move.Cancel(self); + base.Cancel(self); } - public override void Queue( Activity activity ) + public override void Queue(Activity activity) { - move.Queue( activity ); + move.Queue(activity); } - public override Activity Tick( Actor self ) + public override Activity Tick(Actor self) { var mobile = self.Trait(); - var ret = InnerTick( self, mobile ); - mobile.IsMoving = ( ret is MovePart ); + var ret = InnerTick(self, mobile); + mobile.IsMoving = (ret is MovePart); - if( moveFraction > moveFractionTotal ) + if (moveFraction > moveFractionTotal) moveFraction = moveFractionTotal; - UpdateCenterLocation( self, mobile ); + UpdateCenterLocation(self, mobile); return ret; } - Activity InnerTick( Actor self, Mobile mobile ) + Activity InnerTick(Actor self, Mobile mobile) { moveFraction += mobile.MovementSpeedForCell(self, mobile.toCell); - if( moveFraction <= moveFractionTotal ) + if (moveFraction <= moveFractionTotal) return this; - var next = OnComplete( self, mobile, move ); - if( next != null ) + var next = OnComplete(self, mobile, move); + if (next != null) return next; return move; } - void UpdateCenterLocation( Actor self, Mobile mobile ) + void UpdateCenterLocation(Actor self, Mobile mobile) { mobile.PxPosition = PPos.Lerp(from, to, moveFraction, moveFractionTotal); - if( moveFraction >= moveFractionTotal ) + if (moveFraction >= moveFractionTotal) mobile.Facing = toFacing & 0xFF; else - mobile.Facing = int2.Lerp( fromFacing, toFacing, moveFraction, moveFractionTotal ) & 0xFF; + mobile.Facing = int2.Lerp(fromFacing, toFacing, moveFraction, moveFractionTotal) & 0xFF; } - protected abstract MovePart OnComplete( Actor self, Mobile mobile, Move parent ); + protected abstract MovePart OnComplete(Actor self, Mobile mobile, Move parent); - public override IEnumerable GetTargets( Actor self ) + public override IEnumerable GetTargets(Actor self) { return move.GetTargets(self); } @@ -332,50 +347,52 @@ namespace OpenRA.Mods.RA.Move class MoveFirstHalf : MovePart { public MoveFirstHalf(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction) - : base( move, from, to, fromFacing, toFacing, startingFraction ) { } + : base(move, from, to, fromFacing, toFacing, startingFraction) { } - static bool IsTurn( Mobile mobile, CPos nextCell ) + static bool IsTurn(Mobile mobile, CPos nextCell) { return nextCell - mobile.toCell != mobile.toCell - mobile.fromCell; } - protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent ) + protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent) { var fromSubcellOffset = MobileInfo.SubCellOffsets[mobile.fromSubCell]; var toSubcellOffset = MobileInfo.SubCellOffsets[mobile.toSubCell]; - var nextCell = parent.PopPath( self, mobile ); - if( nextCell != null ) + var nextCell = parent.PopPath(self, mobile); + if (nextCell != null) { - if(IsTurn(mobile, nextCell.Value.First)) + if (IsTurn(mobile, nextCell.Value.First)) { var nextSubcellOffset = MobileInfo.SubCellOffsets[nextCell.Value.Second]; var ret = new MoveFirstHalf( move, - Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (fromSubcellOffset + toSubcellOffset) / 2, - Util.BetweenCells( mobile.toCell, nextCell.Value.First ) + (toSubcellOffset + nextSubcellOffset) / 2, + Util.BetweenCells(mobile.fromCell, mobile.toCell) + (fromSubcellOffset + toSubcellOffset) / 2, + Util.BetweenCells(mobile.toCell, nextCell.Value.First) + (toSubcellOffset + nextSubcellOffset) / 2, mobile.Facing, - Util.GetNearestFacing( mobile.Facing, Util.GetFacing( nextCell.Value.First - mobile.toCell, mobile.Facing ) ), - moveFraction - moveFractionTotal ); + Util.GetNearestFacing(mobile.Facing, Util.GetFacing(nextCell.Value.First - mobile.toCell, mobile.Facing)), + moveFraction - moveFractionTotal + ); - mobile.SetLocation( mobile.toCell, mobile.toSubCell, nextCell.Value.First, nextCell.Value.Second); + mobile.SetLocation(mobile.toCell, mobile.toSubCell, nextCell.Value.First, nextCell.Value.Second); return ret; } - parent.path.Add( nextCell.Value.First ); + parent.path.Add(nextCell.Value.First); } var ret2 = new MoveSecondHalf( move, - Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (fromSubcellOffset + toSubcellOffset) / 2, - Util.CenterOfCell( mobile.toCell ) + toSubcellOffset, + Util.BetweenCells(mobile.fromCell, mobile.toCell) + (fromSubcellOffset + toSubcellOffset) / 2, + Util.CenterOfCell(mobile.toCell) + toSubcellOffset, mobile.Facing, mobile.Facing, - moveFraction - moveFractionTotal ); + moveFraction - moveFractionTotal + ); mobile.EnteringCell(self); - mobile.SetLocation( mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell ); + mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell); return ret2; } } @@ -383,14 +400,12 @@ namespace OpenRA.Mods.RA.Move class MoveSecondHalf : MovePart { public MoveSecondHalf(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction) - : base( move, from, to, fromFacing, toFacing, startingFraction ) - { - } + : base(move, from, to, fromFacing, toFacing, startingFraction) {} - protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent ) + protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent) { - mobile.PxPosition = Util.CenterOfCell( mobile.toCell ); - mobile.SetLocation( mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell ); + mobile.PxPosition = Util.CenterOfCell(mobile.toCell); + mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell); mobile.FinishedMoving(self); return null; } @@ -401,7 +416,8 @@ namespace OpenRA.Mods.RA.Move { public static bool IsMoving(this Actor self) { - if (self.IsIdle) return false; + if (self.IsIdle) + return false; Activity a = self.GetCurrentActivity(); Debug.Assert(a != null); diff --git a/OpenRA.Mods.RA/Move/PathFinder.cs b/OpenRA.Mods.RA/Move/PathFinder.cs index 2a7556f1d8..5345bb0702 100755 --- a/OpenRA.Mods.RA/Move/PathFinder.cs +++ b/OpenRA.Mods.RA/Move/PathFinder.cs @@ -68,17 +68,27 @@ namespace OpenRA.Mods.RA.Move } } - public List FindUnitPathToRange(CPos src, CPos target, int range, Actor self) + public List FindUnitPathToRange(CPos src, SubCell srcSub, WPos target, WRange range, Actor self) { using (new PerfSample("Pathfinder")) { var mi = self.Info.Traits.Get(); - var tilesInRange = world.FindTilesInCircle(target, range) - .Where(t => mi.CanEnterCell(self.World, self, t, null, true, true)); + var targetCell = target.ToCPos(); + var rangeSquared = range.Range*range.Range; + + // Correct for SubCell offset + var so = MobileInfo.SubCellOffsets[srcSub]; + target -= new WVec(so.X * 1024 / Game.CellSize, so.Y * 1024 / Game.CellSize, 0); + + // Select only the tiles that are within range from the requested SubCell + // This assumes that the SubCell does not change during the path traversal + var tilesInRange = world.FindTilesInCircle(targetCell, range.Range / 1024 + 1) + .Where(t => (t.CenterPosition - target).LengthSquared <= rangeSquared + && mi.CanEnterCell(self.World, self, t, null, true, true)); var path = FindBidiPath( PathSearch.FromPoints(world, mi, self, tilesInRange, src, true), - PathSearch.FromPoint(world, mi, self, src, target, true).InReverse() + PathSearch.FromPoint(world, mi, self, src, targetCell, true).InReverse() ); return path; diff --git a/OpenRA.Mods.RA/ParaDrop.cs b/OpenRA.Mods.RA/ParaDrop.cs index 9ea27934dc..9adc524ad7 100644 --- a/OpenRA.Mods.RA/ParaDrop.cs +++ b/OpenRA.Mods.RA/ParaDrop.cs @@ -53,7 +53,7 @@ namespace OpenRA.Mods.RA var a = cargo.Unload(self); self.World.AddFrameEndTask(w => w.Add(new Parachute(a, self.CenterPosition))); - Sound.Play(info.ChuteSound, self.CenterLocation); + Sound.Play(info.ChuteSound, self.CenterPosition); } } } diff --git a/OpenRA.Mods.RA/Player/PlaceBuilding.cs b/OpenRA.Mods.RA/Player/PlaceBuilding.cs index cfa783579b..acc8bf2019 100755 --- a/OpenRA.Mods.RA/Player/PlaceBuilding.cs +++ b/OpenRA.Mods.RA/Player/PlaceBuilding.cs @@ -56,7 +56,7 @@ namespace OpenRA.Mods.RA if (playSounds) foreach (var s in buildingInfo.BuildSounds) - Sound.PlayToPlayer(order.Player, s, building.CenterLocation); + Sound.PlayToPlayer(order.Player, s, building.CenterPosition); playSounds = false; } } @@ -74,7 +74,7 @@ namespace OpenRA.Mods.RA new OwnerInit( order.Player ), }); foreach (var s in buildingInfo.BuildSounds) - Sound.PlayToPlayer(order.Player, s, building.CenterLocation); + Sound.PlayToPlayer(order.Player, s, building.CenterPosition); } PlayBuildAnim( self, unit ); diff --git a/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs b/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs index 5e2ec1d079..1abbffcfb0 100755 --- a/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs @@ -29,7 +29,7 @@ namespace OpenRA.Mods.RA.Render public void PlayCharge(Actor self) { - Sound.Play(info.ChargeAudio, self.CenterLocation); + Sound.Play(info.ChargeAudio, self.CenterPosition); anim.PlayThen(NormalizeSequence(self, "active"), () => anim.PlayRepeating(NormalizeSequence(self, "idle"))); } diff --git a/OpenRA.Mods.RA/RepairableNear.cs b/OpenRA.Mods.RA/RepairableNear.cs index 32862bc212..132d001278 100644 --- a/OpenRA.Mods.RA/RepairableNear.cs +++ b/OpenRA.Mods.RA/RepairableNear.cs @@ -69,7 +69,7 @@ namespace OpenRA.Mods.RA var target = Target.FromOrder(order); self.CancelActivity(); - self.QueueActivity(mobile.MoveWithinRange(target, info.CloseEnough)); + self.QueueActivity(mobile.MoveWithinRange(target, new WRange(1024*info.CloseEnough))); self.QueueActivity(new Repair(order.TargetActor)); self.SetTargetLine(target, Color.Green, false); diff --git a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs b/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs index 0890649e9b..50e5a47d17 100755 --- a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs @@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA { self.Trait().PlayCustomAnim(self, "active"); - Sound.Play("ironcur9.aud", order.TargetLocation.ToPPos()); + Sound.Play("ironcur9.aud", order.TargetLocation.CenterPosition); foreach (var target in UnitsInRange(order.TargetLocation) .Where(a => a.Owner.Stances[self.Owner] == Stance.Ally)) diff --git a/OpenRA.Mods.RA/TargetableBuilding.cs b/OpenRA.Mods.RA/TargetableBuilding.cs index 5b75818cee..8bc331338c 100755 --- a/OpenRA.Mods.RA/TargetableBuilding.cs +++ b/OpenRA.Mods.RA/TargetableBuilding.cs @@ -15,25 +15,30 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - class TargetableBuildingInfo : ITraitInfo, Requires + public class TargetableBuildingInfo : ITraitInfo, Requires { public readonly string[] TargetTypes = { }; - public object Create( ActorInitializer init ) { return new TargetableBuilding( this ); } + public object Create(ActorInitializer init) { return new TargetableBuilding(init.self, this); } } - class TargetableBuilding : ITargetable + public class TargetableBuilding : ITargetable { readonly TargetableBuildingInfo info; + readonly Building building; - public TargetableBuilding( TargetableBuildingInfo info ) { this.info = info; } + public TargetableBuilding(Actor self, TargetableBuildingInfo info) + { + this.info = info; + building = self.Trait(); + } public string[] TargetTypes { get { return info.TargetTypes; } } public bool TargetableBy(Actor self, Actor byActor) { return true; } - public IEnumerable TargetableCells( Actor self ) + public IEnumerable TargetablePositions(Actor self) { - return self.Trait().OccupiedCells().Select(c => c.First); + return building.OccupiedCells().Select(c => c.First.CenterPosition); } } } diff --git a/OpenRA.Mods.RA/TargetableSubmarine.cs b/OpenRA.Mods.RA/TargetableSubmarine.cs index 904d1f3b3c..20b34adc50 100644 --- a/OpenRA.Mods.RA/TargetableSubmarine.cs +++ b/OpenRA.Mods.RA/TargetableSubmarine.cs @@ -17,17 +17,22 @@ namespace OpenRA.Mods.RA { public readonly string[] CloakedTargetTypes = {}; - public override object Create( ActorInitializer init ) { return new TargetableSubmarine(init.self, this); } + public override object Create(ActorInitializer init) { return new TargetableSubmarine(init.self, this); } } - public class TargetableSubmarine : TargetableUnit + public class TargetableSubmarine : TargetableUnit { + readonly TargetableSubmarineInfo info; + public TargetableSubmarine(Actor self, TargetableSubmarineInfo info) - : base(self, info) {} + : base(self, info) + { + this.info = info; + } public override string[] TargetTypes { - get { return Cloak.Cloaked ? info.CloakedTargetTypes + get { return cloak.Cloaked ? info.CloakedTargetTypes : info.TargetTypes;} } } diff --git a/OpenRA.Mods.RA/TargetableUnit.cs b/OpenRA.Mods.RA/TargetableUnit.cs index 2cda0fa15a..282e97c8eb 100755 --- a/OpenRA.Mods.RA/TargetableUnit.cs +++ b/OpenRA.Mods.RA/TargetableUnit.cs @@ -18,16 +18,15 @@ namespace OpenRA.Mods.RA { public readonly string[] TargetTypes = { }; - public virtual object Create( ActorInitializer init ) { return new TargetableUnit( init.self, this ); } + public virtual object Create(ActorInitializer init) { return new TargetableUnit(init.self, this); } } - public class TargetableUnit : ITargetable - where Info : TargetableUnitInfo + public class TargetableUnit : ITargetable { - protected readonly Info info; - protected Cloak Cloak; + readonly TargetableUnitInfo info; + protected Cloak cloak; - public TargetableUnit( Actor self, Info info ) + public TargetableUnit(Actor self, TargetableUnitInfo info) { this.info = info; ReceivedCloak(self); @@ -36,15 +35,15 @@ namespace OpenRA.Mods.RA // Arbitrary units can receive cloak via a crate during gameplay public void ReceivedCloak(Actor self) { - Cloak = self.TraitOrDefault(); + cloak = self.TraitOrDefault(); } public virtual bool TargetableBy(Actor self, Actor byActor) { - if (Cloak == null) + if (cloak == null || !cloak.Cloaked) return true; - if (!Cloak.Cloaked || self.Owner == byActor.Owner || self.Owner.Stances[byActor.Owner] == Stance.Ally) + if (self.Owner.IsAlliedWith(byActor.Owner)) return true; return self.World.ActorsWithTrait().Any(a => (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); @@ -52,9 +51,9 @@ namespace OpenRA.Mods.RA public virtual string[] TargetTypes { get { return info.TargetTypes; } } - public virtual IEnumerable TargetableCells( Actor self ) + public virtual IEnumerable TargetablePositions(Actor self) { - yield return self.CenterPosition.ToCPos(); + yield return self.CenterPosition; } } }