diff --git a/OpenRA.FileFormats/WVec.cs b/OpenRA.FileFormats/WVec.cs index 7b450d9d57..72b2df78b9 100644 --- a/OpenRA.FileFormats/WVec.cs +++ b/OpenRA.FileFormats/WVec.cs @@ -36,8 +36,10 @@ namespace OpenRA public static bool operator !=(WVec me, WVec other) { return !(me == other); } public static int Dot(WVec a, WVec b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } - public int LengthSquared { get { return X * X + Y * Y + Z * Z; } } + public long LengthSquared { get { return (long)X * X + (long)Y * Y + (long)Z * Z; } } public int Length { get { return (int)Math.Sqrt(LengthSquared); } } + public long HorizontalLengthSquared { get { return (long)X * X + (long)Y * Y; } } + public int HorizontalLength { get { return (int)Math.Sqrt(HorizontalLengthSquared); } } public WVec Rotate(WRot rot) { diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index a559931c26..dc77cd1e13 100755 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -26,8 +26,6 @@ namespace OpenRA public readonly uint ActorID; Lazy occupySpace; - IHasLocation HasLocation; - Lazy Move; Lazy Facing; public Cached Bounds; @@ -36,25 +34,8 @@ namespace OpenRA public IOccupySpace OccupiesSpace { get { return occupySpace.Value; } } public CPos Location { get { return occupySpace.Value.TopLeft; } } - - public PPos CenterLocation - { - get - { - if (HasLocation == null) - HasLocation = Trait(); - return HasLocation.PxPosition; - } - } - - public WPos CenterPosition - { - get - { - var altitude = Move.Value != null ? Move.Value.Altitude : 0; - return CenterLocation.ToWPos(altitude); - } - } + public PPos CenterLocation { get { return PPos.FromWPos(occupySpace.Value.CenterPosition); } } + public WPos CenterPosition { get { return occupySpace.Value.CenterPosition; } } public WRot Orientation { @@ -93,7 +74,6 @@ namespace OpenRA AddTrait(trait.Create(init)); } - Move = Lazy.New(() => TraitOrDefault()); Facing = Lazy.New(() => TraitOrDefault()); Size = Lazy.New(() => @@ -152,13 +132,14 @@ namespace OpenRA loc += new PVecInt(si.Bounds[2], si.Bounds[3]); } - var move = Move.Value; - if (move != null) + var ios = occupySpace.Value; + if (ios != null) { - loc -= new PVecInt(0, move.Altitude); + var altitude = ios.CenterPosition.Z * Game.CellSize / 1024; + loc -= new PVecInt(0, altitude); if (useAltitude) - size = new PVecInt(size.X, size.Y + move.Altitude); + size = new PVecInt(size.X, size.Y + altitude); } return new Rectangle(loc.X, loc.Y, size.X, size.Y); diff --git a/OpenRA.Game/Traits/Target.cs b/OpenRA.Game/Traits/Target.cs index 2bd84ffd11..6dd8031a0a 100644 --- a/OpenRA.Game/Traits/Target.cs +++ b/OpenRA.Game/Traits/Target.cs @@ -45,8 +45,7 @@ namespace OpenRA.Traits } public bool IsValid { get { return valid && (actor == null || (actor.IsInWorld && !actor.IsDead() && actor.Generation == generation)); } } - public PPos PxPosition { get { return IsActor ? actor.Trait().PxPosition : PPos.FromWPos(pos); } } - public PPos CenterLocation { get { return PxPosition; } } + public PPos CenterLocation { get { return IsActor ? actor.CenterLocation : PPos.FromWPos(pos); } } public Actor Actor { get { return IsActor ? actor : null; } } // TODO: This should return true even if the actor is destroyed @@ -91,12 +90,7 @@ namespace OpenRA.Traits // Target ranges are calculated in 2D, so ignore height differences var rangeSquared = range.Range*range.Range; - return Positions.Any(t => - { - var dx = (long)(t.X - origin.X); - var dy = (long)(t.Y - origin.Y); - return dx*dx + dy*dy <= rangeSquared; - }); + return Positions.Any(t => (t - origin).HorizontalLengthSquared <= rangeSquared); } } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 56ec0c1f01..e979a7ce14 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -96,10 +96,11 @@ namespace OpenRA.Traits public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); } public interface IRadarColorModifier { Color RadarColorOverride(Actor self); } - public interface IHasLocation { PPos PxPosition { get; } } - public interface IOccupySpace : IHasLocation + public interface IOccupySpaceInfo { } + public interface IOccupySpace { + WPos CenterPosition { get; } CPos TopLeft { get; } IEnumerable> OccupiedCells(); } @@ -134,15 +135,14 @@ namespace OpenRA.Traits public interface ITags { IEnumerable GetTags(); } public interface ISelectionBar { float GetValue(); Color GetColor(); } - public interface ITeleportable : IHasLocation /* crap name! */ + public interface IPositionable : IOccupySpace { bool CanEnterCell(CPos location); void SetPosition(Actor self, CPos cell); - void SetPxPosition(Actor self, PPos px); - void AdjustPxPosition(Actor self, PPos px); /* works like SetPxPosition, but visual only */ + void SetPosition(Actor self, WPos pos); + void SetVisualPosition(Actor self, WPos pos); } - public interface IMove : ITeleportable { int Altitude { get; set; } } public interface INotifyBlockingMove { void OnNotifyBlockingMove(Actor self, Actor blocking); } public interface IFacing diff --git a/OpenRA.Game/Traits/Util.cs b/OpenRA.Game/Traits/Util.cs index dc87b9b473..874f84c73a 100755 --- a/OpenRA.Game/Traits/Util.cs +++ b/OpenRA.Game/Traits/Util.cs @@ -100,9 +100,9 @@ namespace OpenRA.Traits return loc.ToPPos() + new PVecInt(Game.CellSize / 2, Game.CellSize / 2); } - public static PPos BetweenCells(CPos from, CPos to) + public static WPos BetweenCells(CPos from, CPos to) { - return PPos.Lerp(CenterOfCell(from), CenterOfCell(to), 1, 2); + return WPos.Lerp(from.CenterPosition, to.CenterPosition, 1, 2); } public static int2 AsInt2(this int[] xs) { return new int2(xs[0], xs[1]); } diff --git a/OpenRA.Game/Traits/Waypoint.cs b/OpenRA.Game/Traits/Waypoint.cs index 96b29fb8f5..2ea8e2a381 100644 --- a/OpenRA.Game/Traits/Waypoint.cs +++ b/OpenRA.Game/Traits/Waypoint.cs @@ -13,7 +13,7 @@ using OpenRA.FileFormats; namespace OpenRA.Traits { - class WaypointInfo : ITraitInfo + class WaypointInfo : ITraitInfo, IOccupySpaceInfo { public object Create( ActorInitializer init ) { return new Waypoint( init ); } } @@ -28,8 +28,7 @@ namespace OpenRA.Traits } public CPos TopLeft { get { return location; } } - public IEnumerable> OccupiedCells() { yield break; } - public PPos PxPosition { get { return Util.CenterOfCell(location); } } + public WPos CenterPosition { get { return location.CenterPosition; } } } } diff --git a/OpenRA.Game/Traits/World/SpatialBins.cs b/OpenRA.Game/Traits/World/SpatialBins.cs index 563311cf6e..a6b17a508c 100644 --- a/OpenRA.Game/Traits/World/SpatialBins.cs +++ b/OpenRA.Game/Traits/World/SpatialBins.cs @@ -45,7 +45,7 @@ namespace OpenRA.Traits for (var i = 0; i <= bins.GetUpperBound(0); i++) bins[i, j].Clear(); - foreach (var a in self.World.ActorsWithTrait()) + foreach (var a in self.World.ActorsWithTrait()) { var bounds = a.Actor.ExtendedBounds.Value; diff --git a/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs index 337438a7fc..b0a27be2cd 100644 --- a/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs +++ b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs @@ -20,7 +20,8 @@ namespace OpenRA.Mods.Cnc { public class HarvesterDockSequence : Activity { - enum State { Wait, Turn, DragIn, Dock, Loop, Undock, DragOut }; + enum State { Wait, Turn, DragIn, Dock, Loop, Undock, DragOut } + static readonly WVec DockOffset = new WVec(-640, 341, 0); readonly Actor proc; readonly Harvester harv; @@ -34,8 +35,8 @@ namespace OpenRA.Mods.Cnc state = State.Turn; harv = self.Trait(); ru = self.Trait(); - startDock = self.Trait().PxPosition.ToWPos(0); - endDock = (proc.Trait().PxPosition + new PVecInt(-15,8)).ToWPos(0); + startDock = self.CenterPosition; + endDock = proc.CenterPosition + DockOffset; } public override Activity Tick(Actor self) @@ -51,7 +52,7 @@ namespace OpenRA.Mods.Cnc state = State.Dock; return Util.SequenceActivities(new Drag(startDock, endDock, 12), this); case State.Dock: - ru.PlayCustomAnimation(self, "dock", () => {ru.PlayCustomAnimRepeating(self, "dock-loop"); state = State.Loop;}); + ru.PlayCustomAnimation(self, "dock", () => { ru.PlayCustomAnimRepeating(self, "dock-loop"); state = State.Loop; }); state = State.Wait; return this; case State.Loop: @@ -65,6 +66,7 @@ namespace OpenRA.Mods.Cnc case State.DragOut: return Util.SequenceActivities(new Drag(endDock, startDock, 12), NextActivity); } + throw new InvalidOperationException("Invalid harvester dock state"); } @@ -73,10 +75,9 @@ namespace OpenRA.Mods.Cnc state = State.Undock; } - public override IEnumerable GetTargets( Actor self ) + public override IEnumerable GetTargets(Actor self) { yield return Target.FromActor(proc); } } -} - +} \ No newline at end of file diff --git a/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs b/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs index 35b81831e8..97fc4f0c66 100644 --- a/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs +++ b/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs @@ -205,7 +205,7 @@ namespace OpenRA.Mods.Cnc.Missions { if (b.Destroyed) return; w2.Add(b); - b.TraitsImplementing().FirstOrDefault().SetPosition(b, a.Location); + b.TraitsImplementing().FirstOrDefault().SetPosition(b, a.Location); b.QueueActivity(mobile.MoveTo(unload, 2)); }); } diff --git a/OpenRA.Mods.Cnc/Missions/Nod01Script.cs b/OpenRA.Mods.Cnc/Missions/Nod01Script.cs index 1f23828606..de88d228f9 100644 --- a/OpenRA.Mods.Cnc/Missions/Nod01Script.cs +++ b/OpenRA.Mods.Cnc/Missions/Nod01Script.cs @@ -1,201 +1,201 @@ -#region Copyright & License Information +#region Copyright & License Information /* - * Copyright 2007-2012 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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 System.Collections.Generic; -using System.Linq; -using OpenRA.Mods.Cnc; -using OpenRA.Mods.RA; -using OpenRA.Mods.RA.Air; -using OpenRA.Mods.RA.Move; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Missions; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Scripting; -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.Cnc.Missions -{ - class Nod01ScriptInfo : TraitInfo, Requires { } - - class Nod01Script : IHasObjectives, IWorldLoaded, ITick - { - public event Action OnObjectivesUpdated = notify => { }; - - public IEnumerable Objectives { get { return new[] { killnikoomba, levelvillage }; } } - - Objective killnikoomba = new Objective(ObjectiveType.Primary, KillNikoombaText, ObjectiveStatus.InProgress); - Objective levelvillage = new Objective(ObjectiveType.Primary, LevelVillageText, ObjectiveStatus.Inactive); - - const string KillNikoombaText = "Find Nikoomba. Once found he must be assasinated."; - const string LevelVillageText = "Nikoomba has met his demise, now level the village."; - - Player gdi; - Player nod; - - //actors and the likes go here - Actor nikoomba; - Actor vil01; - Actor vil02; - Actor vil03; - Actor vil04; - Actor vil05; - Actor vil06; - Actor vil07; - Actor vil08; - Actor vil09; - Actor vil10; - Actor vil11; - Actor vil12; - Actor vil13; - Actor civ01; - Actor civ02; - Actor civ03; - Actor civ04; - Actor civ05; - Actor civ06; - Actor civ07; - - //waypoints - Actor nr1; - Actor nr2; - Actor gr1; - - World world; - - //in the allies01 script stuff was here not needed for me so far - const string NRName = "E1"; - const string GRName = "E2"; - const string GRName2 = "JEEP"; - - void MissionFailed(string text) - { - MissionUtils.CoopMissionFailed(world, text, nod); - } - - void MissionAccomplished(string text) - { - MissionUtils.CoopMissionAccomplished(world, text, nod); - } - - public void Tick(Actor self) - { - if (nod.WinState != WinState.Undefined) return; - - //spawns nod reinf - if (world.FrameNumber == 700) - { - NODReinforceNthA(); - Sound.Play("reinfor1.aud"); - } - if (world.FrameNumber == 1400) - { - NODReinforceNthB(); - Sound.Play("reinfor1.aud"); - } - // objectives - if (killnikoomba.Status == ObjectiveStatus.InProgress) - { - if (nikoomba.Destroyed) - { - killnikoomba.Status = ObjectiveStatus.Completed; - levelvillage.Status = ObjectiveStatus.InProgress; - OnObjectivesUpdated(true); - //DisplayObjective(); - //GDIReinforceNth(); - } - } - if (levelvillage.Status == ObjectiveStatus.InProgress) - { - if (vil01.Destroyed && vil02.Destroyed && vil03.Destroyed && vil04.Destroyed && vil05.Destroyed && vil06.Destroyed && - vil07.Destroyed && vil08.Destroyed && vil09.Destroyed && vil10.Destroyed && vil11.Destroyed && vil12.Destroyed && - vil13.Destroyed && civ01.Destroyed && civ02.Destroyed && civ03.Destroyed && civ04.Destroyed && civ05.Destroyed && - civ06.Destroyed && civ07.Destroyed) - { - levelvillage.Status = ObjectiveStatus.Completed; - OnObjectivesUpdated(true); - MissionAccomplished("Nikoomba was killed and the village was destroyed."); - } - } - - if (!world.Actors.Any(a => (a.Owner == nod) && a.IsInWorld && !a.IsDead())) - { - MissionFailed("The Nod forces in the area have been wiped out."); - } - } - - IEnumerable UnitsNearActor(Actor actor, int range) - { - return world.FindActorsInCircle(actor.CenterPosition, WRange.FromCells(range)) - .Where(a => a.IsInWorld && a != world.WorldActor && !a.Destroyed && a.HasTrait() && !a.Owner.NonCombatant); - } - - void NODReinforceNthA() - { - nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) }); - nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) }); - } - - void NODReinforceNthB() - { - nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) }); - nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) }); - //nr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2))); - } - - void GDIReinforceNth() - { - gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) }); - gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) }); - gr1 = world.CreateActor(true, GRName2, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) }); - //gr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2))); - } - - public void WorldLoaded(World w) - { - world = w; - gdi = w.Players.Single(p => p.InternalName == "GDI"); - nod = w.Players.Single(p => p.InternalName == "NOD"); - var actors = w.WorldActor.Trait().Actors; - nikoomba = actors["Nikoomba"]; - vil01 = actors["Vil01"]; - vil02 = actors["Vil02"]; - vil03 = actors["Vil03"]; - vil04 = actors["Vil04"]; - vil05 = actors["Vil05"]; - vil06 = actors["Vil06"]; - vil07 = actors["Vil07"]; - vil08 = actors["Vil08"]; - vil09 = actors["Vil09"]; - vil10 = actors["Vil10"]; - vil11 = actors["Vil11"]; - vil12 = actors["Vil12"]; - vil13 = actors["Vil13"]; - civ01 = actors["Civ01"]; - civ02 = actors["Civ02"]; - civ03 = actors["Civ03"]; - civ04 = actors["Civ04"]; - civ05 = actors["Civ05"]; - civ06 = actors["Civ06"]; - civ07 = actors["Civ07"]; - nr1 = actors["NODReinforceNthA"]; - nr2 = actors["NODReinforceNthB"]; - gr1 = actors["GDIReinforceNth"]; - Game.MoveViewport(nr1.Location.ToFloat2()); - Action afterFMV = () => - { - Sound.PlayMusic(Rules.Music["aoi"]); - }; - Game.RunAfterDelay(0, () => Media.PlayFMVFullscreen(w, "nod1pre.vqa", () => - Media.PlayFMVFullscreen(w, "nod1.vqa", afterFMV))); - } - } -} + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Mods.Cnc; +using OpenRA.Mods.RA; +using OpenRA.Mods.RA.Air; +using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Missions; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Scripting; +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.Cnc.Missions +{ + class Nod01ScriptInfo : TraitInfo, Requires { } + + class Nod01Script : IHasObjectives, IWorldLoaded, ITick + { + public event Action OnObjectivesUpdated = notify => { }; + + public IEnumerable Objectives { get { return new[] { killnikoomba, levelvillage }; } } + + Objective killnikoomba = new Objective(ObjectiveType.Primary, KillNikoombaText, ObjectiveStatus.InProgress); + Objective levelvillage = new Objective(ObjectiveType.Primary, LevelVillageText, ObjectiveStatus.Inactive); + + const string KillNikoombaText = "Find Nikoomba. Once found he must be assasinated."; + const string LevelVillageText = "Nikoomba has met his demise, now level the village."; + + Player gdi; + Player nod; + + //actors and the likes go here + Actor nikoomba; + Actor vil01; + Actor vil02; + Actor vil03; + Actor vil04; + Actor vil05; + Actor vil06; + Actor vil07; + Actor vil08; + Actor vil09; + Actor vil10; + Actor vil11; + Actor vil12; + Actor vil13; + Actor civ01; + Actor civ02; + Actor civ03; + Actor civ04; + Actor civ05; + Actor civ06; + Actor civ07; + + //waypoints + Actor nr1; + Actor nr2; + Actor gr1; + + World world; + + //in the allies01 script stuff was here not needed for me so far + const string NRName = "E1"; + const string GRName = "E2"; + const string GRName2 = "JEEP"; + + void MissionFailed(string text) + { + MissionUtils.CoopMissionFailed(world, text, nod); + } + + void MissionAccomplished(string text) + { + MissionUtils.CoopMissionAccomplished(world, text, nod); + } + + public void Tick(Actor self) + { + if (nod.WinState != WinState.Undefined) return; + + //spawns nod reinf + if (world.FrameNumber == 700) + { + NODReinforceNthA(); + Sound.Play("reinfor1.aud"); + } + if (world.FrameNumber == 1400) + { + NODReinforceNthB(); + Sound.Play("reinfor1.aud"); + } + // objectives + if (killnikoomba.Status == ObjectiveStatus.InProgress) + { + if (nikoomba.Destroyed) + { + killnikoomba.Status = ObjectiveStatus.Completed; + levelvillage.Status = ObjectiveStatus.InProgress; + OnObjectivesUpdated(true); + //DisplayObjective(); + //GDIReinforceNth(); + } + } + if (levelvillage.Status == ObjectiveStatus.InProgress) + { + if (vil01.Destroyed && vil02.Destroyed && vil03.Destroyed && vil04.Destroyed && vil05.Destroyed && vil06.Destroyed && + vil07.Destroyed && vil08.Destroyed && vil09.Destroyed && vil10.Destroyed && vil11.Destroyed && vil12.Destroyed && + vil13.Destroyed && civ01.Destroyed && civ02.Destroyed && civ03.Destroyed && civ04.Destroyed && civ05.Destroyed && + civ06.Destroyed && civ07.Destroyed) + { + levelvillage.Status = ObjectiveStatus.Completed; + OnObjectivesUpdated(true); + MissionAccomplished("Nikoomba was killed and the village was destroyed."); + } + } + + if (!world.Actors.Any(a => (a.Owner == nod) && a.IsInWorld && !a.IsDead())) + { + MissionFailed("The Nod forces in the area have been wiped out."); + } + } + + IEnumerable UnitsNearActor(Actor actor, int range) + { + return world.FindActorsInCircle(actor.CenterPosition, WRange.FromCells(range)) + .Where(a => a.IsInWorld && a != world.WorldActor && !a.Destroyed && a.HasTrait() && !a.Owner.NonCombatant); + } + + void NODReinforceNthA() + { + nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) }); + nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) }); + } + + void NODReinforceNthB() + { + nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) }); + nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) }); + //nr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2))); + } + + void GDIReinforceNth() + { + gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) }); + gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) }); + gr1 = world.CreateActor(true, GRName2, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) }); + //gr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2))); + } + + public void WorldLoaded(World w) + { + world = w; + gdi = w.Players.Single(p => p.InternalName == "GDI"); + nod = w.Players.Single(p => p.InternalName == "NOD"); + var actors = w.WorldActor.Trait().Actors; + nikoomba = actors["Nikoomba"]; + vil01 = actors["Vil01"]; + vil02 = actors["Vil02"]; + vil03 = actors["Vil03"]; + vil04 = actors["Vil04"]; + vil05 = actors["Vil05"]; + vil06 = actors["Vil06"]; + vil07 = actors["Vil07"]; + vil08 = actors["Vil08"]; + vil09 = actors["Vil09"]; + vil10 = actors["Vil10"]; + vil11 = actors["Vil11"]; + vil12 = actors["Vil12"]; + vil13 = actors["Vil13"]; + civ01 = actors["Civ01"]; + civ02 = actors["Civ02"]; + civ03 = actors["Civ03"]; + civ04 = actors["Civ04"]; + civ05 = actors["Civ05"]; + civ06 = actors["Civ06"]; + civ07 = actors["Civ07"]; + nr1 = actors["NODReinforceNthA"]; + nr2 = actors["NODReinforceNthB"]; + gr1 = actors["GDIReinforceNth"]; + Game.MoveViewport(nr1.Location.ToFloat2()); + Action afterFMV = () => + { + Sound.PlayMusic(Rules.Music["aoi"]); + }; + Game.RunAfterDelay(0, () => Media.PlayFMVFullscreen(w, "nod1pre.vqa", () => + Media.PlayFMVFullscreen(w, "nod1.vqa", afterFMV))); + } + } +} diff --git a/OpenRA.Mods.RA/AI/HackyAI.cs b/OpenRA.Mods.RA/AI/HackyAI.cs index 394510ae82..c0201ce051 100644 --- a/OpenRA.Mods.RA/AI/HackyAI.cs +++ b/OpenRA.Mods.RA/AI/HackyAI.cs @@ -763,7 +763,7 @@ namespace OpenRA.Mods.RA.AI if (!buildableThings.Any()) return null; var myUnits = p.World - .ActorsWithTrait() + .ActorsWithTrait() .Where(a => a.Actor.Owner == p) .Select(a => a.Actor.Info.Name).ToArray(); @@ -783,7 +783,7 @@ namespace OpenRA.Mods.RA.AI int CountUnits(string unit, Player owner) { - return world.ActorsWithTrait().Where(a => a.Actor.Owner == owner && a.Actor.Info.Name == unit).Count(); + return world.ActorsWithTrait().Where(a => a.Actor.Owner == owner && a.Actor.Info.Name == unit).Count(); } int? CountBuildingByCommonName(string commonName, Player owner) @@ -1028,7 +1028,7 @@ namespace OpenRA.Mods.RA.AI { var allEnemyUnits = world.Actors .Where(unit => p.Stances[unit.Owner] == Stance.Enemy && !unit.HasTrait() && - unit.HasTrait() && unit.HasTrait()).ToList(); + unit.HasTrait()).ToList(); if (allEnemyUnits.Count > 0) return allEnemyUnits.ClosestTo(pos); @@ -1048,14 +1048,14 @@ namespace OpenRA.Mods.RA.AI List FindEnemyConstructionYards() { - var bases = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy && a.HasTrait() - && !a.Destroyed && a.HasTrait() && !a.HasTrait()).ToList(); + var bases = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy && !a.Destroyed + && a.HasTrait() && !a.HasTrait()).ToList(); return bases != null ? bases : new List(); } Actor FindEnemyBuildingClosestToPos(WPos pos) { - var closestBuilding = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy && a.HasTrait() + var closestBuilding = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy && !a.Destroyed && a.HasTrait()).ClosestTo(pos); return closestBuilding; } @@ -1145,7 +1145,7 @@ namespace OpenRA.Mods.RA.AI void FindNewUnits(Actor self) { - var newUnits = self.World.ActorsWithTrait() + var newUnits = self.World.ActorsWithTrait() .Where(a => a.Actor.Owner == p && !a.Actor.HasTrait() && !activeUnits.Contains(a.Actor)) .Select(a => a.Actor).ToArray(); @@ -1424,12 +1424,12 @@ namespace OpenRA.Mods.RA.AI aggro[e.Attacker.Owner].Aggro += e.Damage; //protected harvesters or building - if (self.HasTrait() || self.HasTrait()) - if (e.Attacker.HasTrait() && (p.Stances[e.Attacker.Owner] == Stance.Enemy)) - { - defenseCenter = e.Attacker.Location; - ProtectOwn(e.Attacker); - } + if ((self.HasTrait() || self.HasTrait()) && + p.Stances[e.Attacker.Owner] == Stance.Enemy) + { + defenseCenter = e.Attacker.Location; + ProtectOwn(e.Attacker); + } } } } diff --git a/OpenRA.Mods.RA/Activities/Enter.cs b/OpenRA.Mods.RA/Activities/Enter.cs index fbf2243139..c4afe104b5 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -37,8 +37,8 @@ namespace OpenRA.Mods.RA.Activities var mobile = self.Trait(); var to = target.CenterPosition; var from = self.CenterPosition; - var speed = mobile.WorldMovementSpeedForCell(self, self.Location); - var length = speed > 0 ? (int)((to - from).Length * 3 / speed) : 0; + var speed = mobile.MovementSpeedForCell(self, self.Location); + var length = speed > 0 ? (to - from).Length / speed : 0; return Util.SequenceActivities( new Turn(Util.GetFacing(to - from, mobile.Facing)), diff --git a/OpenRA.Mods.RA/Activities/Leap.cs b/OpenRA.Mods.RA/Activities/Leap.cs index 7be3de70d2..9ab86d9335 100644 --- a/OpenRA.Mods.RA/Activities/Leap.cs +++ b/OpenRA.Mods.RA/Activities/Leap.cs @@ -41,8 +41,7 @@ namespace OpenRA.Mods.RA.Activities mobile.IsMoving = true; from = self.CenterPosition; - var offset = MobileInfo.SubCellOffsets[targetMobile.fromSubCell]; - to = targetMobile.fromCell.CenterPosition + new WVec(offset.X * 1024 / Game.CellSize, offset.Y * 1024 / Game.CellSize, 0); + to = targetMobile.fromCell.CenterPosition + MobileInfo.SubCellOffsets[targetMobile.fromSubCell]; length = Math.Max((to - from).Length / speed.Range, 1); self.Trait().Attacking(self, Target.FromActor(target)); @@ -56,7 +55,7 @@ namespace OpenRA.Mods.RA.Activities if (ticks == 0 && IsCanceled) return NextActivity; - mobile.AdjustPxPosition(self, PPos.FromWPosHackZ(WPos.LerpQuadratic(from, to, angle, ++ticks, length))); + mobile.SetVisualPosition(self, WPos.LerpQuadratic(from, to, angle, ++ticks, length)); if (ticks >= length) { mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell); diff --git a/OpenRA.Mods.RA/Activities/Teleport.cs b/OpenRA.Mods.RA/Activities/Teleport.cs index 0b58ab398e..39ad10bd0d 100755 --- a/OpenRA.Mods.RA/Activities/Teleport.cs +++ b/OpenRA.Mods.RA/Activities/Teleport.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -34,7 +34,7 @@ namespace OpenRA.Mods.RA.Activities Sound.Play(sound, self.CenterPosition); Sound.Play(sound, destination.CenterPosition); - self.Trait().SetPosition(self, destination); + self.Trait().SetPosition(self, destination); self.Generation++; if (killCargo && self.HasTrait()) @@ -68,7 +68,7 @@ namespace OpenRA.Mods.RA.Activities public override Activity Tick(Actor self) { - self.Trait().SetPosition(self, destination); + self.Trait().SetPosition(self, destination); self.Generation++; return NextActivity; } diff --git a/OpenRA.Mods.RA/Activities/UnloadCargo.cs b/OpenRA.Mods.RA/Activities/UnloadCargo.cs index e4cba01ee2..1d5b7f328d 100644 --- a/OpenRA.Mods.RA/Activities/UnloadCargo.cs +++ b/OpenRA.Mods.RA/Activities/UnloadCargo.cs @@ -90,9 +90,9 @@ namespace OpenRA.Mods.RA.Activities var mobile = actor.Trait(); mobile.Facing = Util.GetFacing(exit - current, mobile.Facing ); mobile.SetPosition(actor, exitTile.Value); - mobile.AdjustPxPosition(actor, PPos.FromWPos(current)); - var speed = mobile.WorldMovementSpeedForCell(actor, exitTile.Value); - var length = speed > 0 ? ((int)(exit - current).Length * 3 / speed) : 0; + mobile.SetVisualPosition(actor, current); + var speed = mobile.MovementSpeedForCell(actor, exitTile.Value); + var length = speed > 0 ? (exit - current).Length / speed : 0; w.Add(actor); actor.CancelActivity(); diff --git a/OpenRA.Mods.RA/Air/Aircraft.cs b/OpenRA.Mods.RA/Air/Aircraft.cs index 7c8f0f8feb..b9b407b1c4 100755 --- a/OpenRA.Mods.RA/Air/Aircraft.cs +++ b/OpenRA.Mods.RA/Air/Aircraft.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -19,10 +19,10 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Air { - - public class AircraftInfo : ITraitInfo, IFacingInfo, UsesInit, UsesInit, UsesInit + public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit, UsesInit, UsesInit { public readonly int CruiseAltitude = 30; + [ActorReference] public readonly string[] RepairBuildings = { "fix" }; [ActorReference] @@ -32,56 +32,47 @@ namespace OpenRA.Mods.RA.Air public readonly int Speed = 1; public readonly string[] LandableTerrainTypes = { }; - public virtual object Create( ActorInitializer init ) { return new Aircraft( init , this ); } + public virtual object Create(ActorInitializer init) { return new Aircraft(init, this); } public int GetInitialFacing() { return InitialFacing; } } - public class Aircraft : IMove, IFacing, IOccupySpace, ISync, INotifyKilled, IIssueOrder, IOrderVoice + public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice { - public IDisposable reservation; + static readonly Pair[] NoCells = new Pair[] { }; - public void UnReserve() - { - if (reservation != null) - { - reservation.Dispose(); - reservation = null; - } - } + readonly AircraftInfo info; + readonly Actor self; - public void Killed(Actor self, AttackInfo e) - { - UnReserve(); - } - - - protected readonly Actor self; [Sync] public int Facing { get; set; } - [Sync] public int Altitude { get; set; } - [Sync] public PSubPos SubPxPosition; - public PPos PxPosition { get { return SubPxPosition.ToPPos(); } } - public CPos TopLeft { get { return PxPosition.ToCPos(); } } + [Sync] public WPos CenterPosition { get; private set; } + public CPos TopLeft { get { return CenterPosition.ToCPos(); } } + public IDisposable Reservation; + public int ROT { get { return info.ROT; } } - readonly AircraftInfo Info; - - public Aircraft(ActorInitializer init , AircraftInfo info) + public Aircraft(ActorInitializer init, AircraftInfo info) { + this.info = info; this.self = init.self; - if( init.Contains() ) - this.SubPxPosition = Util.CenterOfCell( init.Get() ).ToPSubPos(); - this.Facing = init.Contains() ? init.Get() : info.InitialFacing; - this.Altitude = init.Contains() ? init.Get() : 0; - Info = info; + if (init.Contains()) + SetPosition(self, init.Get()); + + this.Facing = init.Contains() ? init.Get() : info.InitialFacing; + + if (init.Contains()) + { + var z = init.Get() * 1024 / Game.CellSize; + SetPosition(self, CenterPosition + new WVec(0, 0, z - CenterPosition.Z)); + } } public Actor GetActorBelow() { - if (self.Trait().Altitude != 0) + if (self.CenterPosition.Z != 0) return null; // not on the ground. return self.World.FindActorsInBox(self.CenterPosition, self.CenterPosition) - .FirstOrDefault( a => a.HasTrait() ); + .FirstOrDefault(a => a.HasTrait()); } protected void ReserveSpawnBuilding() @@ -93,28 +84,39 @@ namespace OpenRA.Mods.RA.Air var res = afld.Trait(); if (res != null) - reservation = res.Reserve(afld, self, this); + Reservation = res.Reserve(afld, self, this); } - public int ROT { get { return Info.ROT; } } + public void UnReserve() + { + if (Reservation != null) + { + Reservation.Dispose(); + Reservation = null; + } + } + + public void Killed(Actor self, AttackInfo e) + { + UnReserve(); + } public void SetPosition(Actor self, CPos cell) { - SetPxPosition(self, Util.CenterOfCell(cell)); + // Changes position, but not altitude + CenterPosition = cell.CenterPosition + new WVec(0, 0, CenterPosition.Z); } - public void SetPxPosition(Actor self, PPos px) - { - SubPxPosition = px.ToPSubPos(); - } - - public void AdjustPxPosition(Actor self, PPos px) { SetPxPosition(self, px); } + public void SetPosition(Actor self, WPos pos) { CenterPosition = pos; } + public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos); } public bool AircraftCanEnter(Actor a) { - if (self.AppearsHostileTo(a)) return false; - return Info.RearmBuildings.Contains(a.Info.Name) - || Info.RepairBuildings.Contains(a.Info.Name); + if (self.AppearsHostileTo(a)) + return false; + + return info.RearmBuildings.Contains(a.Info.Name) + || info.RepairBuildings.Contains(a.Info.Name); } public bool CanEnterCell(CPos location) { return true; } @@ -123,20 +125,20 @@ namespace OpenRA.Mods.RA.Air { get { - decimal ret = Info.Speed; + decimal ret = info.Speed; foreach (var t in self.TraitsImplementing()) ret *= t.GetSpeedModifier(); return (int)ret; } } - Pair[] noCells = new Pair[] { }; - public IEnumerable> OccupiedCells() { return noCells; } + public IEnumerable> OccupiedCells() { return NoCells; } - public void TickMove(int speed, int facing) + public WVec FlyStep(int facing) { - var rawspeed = speed * 7 / (32 * PSubPos.PerPx); - SubPxPosition += rawspeed * -Util.SubPxVector[facing]; + var speed = MovementSpeed * 7 * 1024 / (Game.CellSize * 32); + var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)); + return speed * dir / 1024; } public bool CanLand(CPos cell) @@ -148,15 +150,15 @@ namespace OpenRA.Mods.RA.Air return false; var type = self.World.GetTerrainType(cell); - return Info.LandableTerrainTypes.Contains(type); + return info.LandableTerrainTypes.Contains(type); } public IEnumerable GetResupplyActivities(Actor a) { var name = a.Info.Name; - if (Info.RearmBuildings.Contains(name)) + if (info.RearmBuildings.Contains(name)) yield return new Rearm(self); - if (Info.RepairBuildings.Contains(name)) + if (info.RepairBuildings.Contains(name)) yield return new Repair(a); } @@ -226,6 +228,7 @@ namespace OpenRA.Mods.RA.Air cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked"; return true; } + public bool IsQueued { get; protected set; } } } diff --git a/OpenRA.Mods.RA/Air/AttackPlane.cs b/OpenRA.Mods.RA/Air/AttackPlane.cs index b23da20bd6..fce0c636af 100755 --- a/OpenRA.Mods.RA/Air/AttackPlane.cs +++ b/OpenRA.Mods.RA/Air/AttackPlane.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -24,14 +24,13 @@ namespace OpenRA.Mods.RA.Air public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove) { - return new FlyAttack( newTarget ); + return new FlyAttack(newTarget); } protected override bool CanAttack(Actor self, Target target) { // dont fire while landed - return base.CanAttack(self, target) - && self.Trait().Altitude > 0; + return base.CanAttack(self, target) && self.CenterPosition.Z > 0; } } } diff --git a/OpenRA.Mods.RA/Air/EjectOnDeath.cs b/OpenRA.Mods.RA/Air/EjectOnDeath.cs index 74cf19de12..e6d213c0e6 100644 --- a/OpenRA.Mods.RA/Air/EjectOnDeath.cs +++ b/OpenRA.Mods.RA/Air/EjectOnDeath.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -20,6 +20,7 @@ namespace OpenRA.Mods.RA public readonly string PilotActor = "E1"; public readonly int SuccessRate = 50; public readonly string ChuteSound = "chute1.aud"; + public readonly WRange MinimumEjectHeight = new WRange(427); } public class EjectOnDeath : INotifyKilled @@ -29,14 +30,15 @@ namespace OpenRA.Mods.RA var info = self.Info.Traits.Get(); var pilot = self.World.CreateActor(false, info.PilotActor.ToLowerInvariant(), new TypeDictionary { new OwnerInit(self.Owner) }); - var r = self.World.SharedRandom.Next(1, 100); - var aircraft = self.Trait(); - if (IsSuitableCell(pilot, self.Location) && r > 100 - info.SuccessRate && aircraft.Altitude > 10 + var r = self.World.SharedRandom.Next(1, 100); + var cp = self.CenterPosition; + + if (IsSuitableCell(pilot, self.Location) && r > 100 - info.SuccessRate && cp.Z > info.MinimumEjectHeight.Range && self.Owner.WinState != WinState.Lost) { - self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot, self.CenterPosition))); - Sound.Play(info.ChuteSound, self.CenterPosition); + self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot, cp))); + Sound.Play(info.ChuteSound, cp); } else pilot.Destroy(); @@ -44,7 +46,7 @@ namespace OpenRA.Mods.RA bool IsSuitableCell(Actor actorToDrop, CPos p) { - return actorToDrop.Trait().CanEnterCell(p); + return actorToDrop.Trait().CanEnterCell(p); } } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Air/FallsToEarth.cs b/OpenRA.Mods.RA/Air/FallsToEarth.cs index 9f62efcc01..5099953e2f 100755 --- a/OpenRA.Mods.RA/Air/FallsToEarth.cs +++ b/OpenRA.Mods.RA/Air/FallsToEarth.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -19,6 +19,7 @@ namespace OpenRA.Mods.RA.Air public readonly bool Spins = true; public readonly bool Moves = false; + public readonly WRange Velocity = new WRange(43); public object Create(ActorInitializer init) { return new FallsToEarth(init.self, this); } } @@ -47,7 +48,7 @@ namespace OpenRA.Mods.RA.Air public override Activity Tick(Actor self) { var aircraft = self.Trait(); - if (aircraft.Altitude <= 0) + if (self.CenterPosition.Z <= 0) { if (info.Explosion != null) Combat.DoExplosion(self, info.Explosion, self.CenterPosition); @@ -62,15 +63,14 @@ namespace OpenRA.Mods.RA.Air aircraft.Facing = (aircraft.Facing + spin) % 256; } - if (info.Moves) - FlyUtil.Fly(self, aircraft.Altitude); - - aircraft.Altitude--; + var move = info.Moves ? aircraft.FlyStep(aircraft.Facing) : WVec.Zero; + move -= new WVec(WRange.Zero, WRange.Zero, info.Velocity); + aircraft.SetPosition(self, aircraft.CenterPosition + move); return this; } // Cannot be cancelled - public override void Cancel( Actor self ) { } + public override void Cancel(Actor self) { } } } diff --git a/OpenRA.Mods.RA/Air/Fly.cs b/OpenRA.Mods.RA/Air/Fly.cs index 09f2ca2d81..198ea181d0 100755 --- a/OpenRA.Mods.RA/Air/Fly.cs +++ b/OpenRA.Mods.RA/Air/Fly.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -16,49 +16,56 @@ namespace OpenRA.Mods.RA.Air { public class Fly : Activity { - public readonly PPos Pos; + readonly WPos pos; - Fly(PPos px) { Pos = px; } + Fly(WPos pos) { this.pos = pos; } - public static Fly ToPx( PPos px ) { return new Fly( px ); } - public static Fly ToCell(CPos pos) { return new Fly(Util.CenterOfCell(pos)); } + public static void FlyToward(Actor self, Plane plane, int desiredFacing, WRange desiredAltitude) + { + var move = plane.FlyStep(plane.Facing); + var altitude = plane.CenterPosition.Z; + + plane.Facing = Util.TickFacing(plane.Facing, desiredFacing, plane.ROT); + + if (altitude != desiredAltitude.Range) + { + var delta = move.HorizontalLength * plane.Info.MaximumPitch.Tan() / 1024; + var dz = (desiredAltitude.Range - altitude).Clamp(-delta, delta); + move += new WVec(0, 0, dz); + } + + plane.SetPosition(self, plane.CenterPosition + move); + } + + public static Fly ToPos(WPos pos) { return new Fly(pos); } + public static Fly ToCell(CPos pos) { return new Fly(pos.CenterPosition); } public override Activity Tick(Actor self) { - var cruiseAltitude = self.Info.Traits.Get().CruiseAltitude; - - if (IsCanceled) return NextActivity; - - var d = Pos - self.CenterLocation; - if (d.LengthSquared < 50) /* close enough */ + if (IsCanceled) return NextActivity; - var aircraft = self.Trait(); + // Close enough (ported from old code which checked length against sqrt(50) px) + var d = pos - self.CenterPosition; + if (d.HorizontalLengthSquared < 91022) + return NextActivity; - var desiredFacing = Util.GetFacing(d, aircraft.Facing); - if (aircraft.Altitude == cruiseAltitude) - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); + var plane = self.Trait(); + var desiredFacing = Util.GetFacing(d, plane.Facing); + var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize); - if (aircraft.Altitude < cruiseAltitude) - ++aircraft.Altitude; + // Don't turn until we've reached the cruise altitude + if (plane.CenterPosition.Z < cruiseAltitude.Range) + desiredFacing = plane.Facing; + + FlyToward(self, plane, desiredFacing, cruiseAltitude); - FlyUtil.Fly(self, cruiseAltitude); return this; } - public override IEnumerable GetTargets( Actor self ) + public override IEnumerable GetTargets(Actor self) { - yield return Target.FromPos(Pos); - } - } - - public static class FlyUtil - { - public static void Fly(Actor self, int desiredAltitude ) - { - var aircraft = self.Trait(); - aircraft.TickMove( PSubPos.PerPx * aircraft.MovementSpeed, aircraft.Facing ); - aircraft.Altitude += Math.Sign(desiredAltitude - aircraft.Altitude); + yield return Target.FromPos(pos); } } } diff --git a/OpenRA.Mods.RA/Air/FlyAttack.cs b/OpenRA.Mods.RA/Air/FlyAttack.cs index 43cc94fa9c..1e577804f4 100755 --- a/OpenRA.Mods.RA/Air/FlyAttack.cs +++ b/OpenRA.Mods.RA/Air/FlyAttack.cs @@ -14,43 +14,41 @@ namespace OpenRA.Mods.RA.Air { public class FlyAttack : Activity { - readonly Target Target; + readonly Target target; Activity inner; - public FlyAttack(Target target) { Target = target; } + public FlyAttack(Target target) { this.target = target; } public override Activity Tick(Actor self) { - if( !Target.IsValid ) - Cancel( self ); + if (!target.IsValid) + Cancel(self); + var limitedAmmo = self.TraitOrDefault(); - if( limitedAmmo != null && !limitedAmmo.HasAmmo() ) - Cancel( self ); + if (limitedAmmo != null && !limitedAmmo.HasAmmo()) + Cancel(self); var attack = self.TraitOrDefault(); if (attack != null) - attack.DoAttack( self, Target ); + attack.DoAttack(self, target); - if( inner == null ) + if (inner == null) { - if( IsCanceled ) + if (IsCanceled) return NextActivity; - inner = Util.SequenceActivities( - Fly.ToPx(Target.CenterLocation), - new FlyTimed(50)); + + inner = Util.SequenceActivities(Fly.ToPos(target.CenterPosition), new FlyTimed(50)); } - inner = Util.RunActivity( self, inner ); + + inner = Util.RunActivity(self, inner); return this; } - public override void Cancel( Actor self ) + public override void Cancel(Actor self) { - if( !IsCanceled ) - { - if( inner != null ) - inner.Cancel( self ); - } + if (!IsCanceled && inner != null) + inner.Cancel(self); // NextActivity must always be set to null: base.Cancel(self); diff --git a/OpenRA.Mods.RA/Air/FlyCircle.cs b/OpenRA.Mods.RA/Air/FlyCircle.cs index 24c92d2ad1..9302a5e951 100644 --- a/OpenRA.Mods.RA/Air/FlyCircle.cs +++ b/OpenRA.Mods.RA/Air/FlyCircle.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -17,20 +17,16 @@ namespace OpenRA.Mods.RA.Air { public override Activity Tick(Actor self) { - var cruiseAltitude = self.Info.Traits.Get().CruiseAltitude; + if (IsCanceled) + return NextActivity; - if (IsCanceled) return NextActivity; + var plane = self.Trait(); - var aircraft = self.Trait(); + // We can't possibly turn this fast + var desiredFacing = plane.Facing + 64; + var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize); + Fly.FlyToward(self, plane, desiredFacing, cruiseAltitude); - var desiredFacing = aircraft.Facing + 64; // we can't possibly turn this fast. - if (aircraft.Altitude == cruiseAltitude) - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); - - if (aircraft.Altitude < cruiseAltitude) - ++aircraft.Altitude; - - FlyUtil.Fly(self, cruiseAltitude); return this; } } diff --git a/OpenRA.Mods.RA/Air/FlyTimed.cs b/OpenRA.Mods.RA/Air/FlyTimed.cs index 7968d5a9d7..03ee64688f 100755 --- a/OpenRA.Mods.RA/Air/FlyTimed.cs +++ b/OpenRA.Mods.RA/Air/FlyTimed.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -20,10 +20,13 @@ namespace OpenRA.Mods.RA.Air public override Activity Tick(Actor self) { - if( IsCanceled ) return NextActivity; - var targetAltitude = self.Info.Traits.Get().CruiseAltitude; - if (remainingTicks-- == 0) return NextActivity; - FlyUtil.Fly(self, targetAltitude); + if (IsCanceled || remainingTicks-- == 0) + return NextActivity; + + var plane = self.Trait(); + var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize); + Fly.FlyToward(self, plane, plane.Facing, cruiseAltitude); + return this; } } @@ -32,15 +35,16 @@ namespace OpenRA.Mods.RA.Air { public override Activity Tick(Actor self) { - var targetAltitude = self.Info.Traits.Get().CruiseAltitude; if (IsCanceled || !self.World.Map.IsInMap(self.Location)) return NextActivity; - FlyUtil.Fly(self, targetAltitude); + var plane = self.Trait(); + var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize); + Fly.FlyToward(self, plane, plane.Facing, cruiseAltitude); return this; } - public override void Cancel( Actor self ) + public override void Cancel(Actor self) { base.Cancel(self); } diff --git a/OpenRA.Mods.RA/Air/HeliAttack.cs b/OpenRA.Mods.RA/Air/HeliAttack.cs index 87e3de5eed..1ba4d4d417 100755 --- a/OpenRA.Mods.RA/Air/HeliAttack.cs +++ b/OpenRA.Mods.RA/Air/HeliAttack.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -17,36 +17,35 @@ namespace OpenRA.Mods.RA.Air public class HeliAttack : Activity { Target target; - public HeliAttack( Target target ) { this.target = target; } + public HeliAttack(Target target) { this.target = target; } public override Activity Tick(Actor self) { - if (IsCanceled) return NextActivity; - if (!target.IsValid) return NextActivity; + if (IsCanceled || !target.IsValid) + return NextActivity; var limitedAmmo = self.TraitOrDefault(); var reloads = self.TraitOrDefault(); if (limitedAmmo != null && !limitedAmmo.HasAmmo() && reloads == null) - return Util.SequenceActivities( new HeliReturn(), NextActivity ); - - var aircraft = self.Trait(); - var info = self.Info.Traits.Get(); - if (aircraft.Altitude != info.CruiseAltitude) - { - aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude); - return this; - } + return Util.SequenceActivities(new HeliReturn(), NextActivity); + var helicopter = self.Trait(); var attack = self.Trait(); var dist = target.CenterPosition - self.CenterPosition; - var desiredFacing = Util.GetFacing(dist, aircraft.Facing); - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); + // Can rotate facing while ascending + var desiredFacing = Util.GetFacing(dist, helicopter.Facing); + helicopter.Facing = Util.TickFacing(helicopter.Facing, desiredFacing, helicopter.ROT); + var cruiseAltitude = new WRange(helicopter.Info.CruiseAltitude * 1024 / Game.CellSize); + if (HeliFly.AdjustAltitude(self, helicopter, cruiseAltitude)) + return this; + + // Fly towards the target if (!target.IsInRange(self.CenterPosition, attack.GetMaximumRange())) - aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, desiredFacing); + helicopter.SetPosition(self, helicopter.CenterPosition + helicopter.FlyStep(desiredFacing)); - attack.DoAttack( self, target ); + attack.DoAttack(self, target); return this; } diff --git a/OpenRA.Mods.RA/Air/HeliFly.cs b/OpenRA.Mods.RA/Air/HeliFly.cs index b0962801dd..f4ac312b23 100755 --- a/OpenRA.Mods.RA/Air/HeliFly.cs +++ b/OpenRA.Mods.RA/Air/HeliFly.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -16,42 +16,56 @@ namespace OpenRA.Mods.RA.Air { class HeliFly : Activity { - public readonly PPos Dest; - public HeliFly(PPos dest) + readonly WPos pos; + + public HeliFly(WPos pos) { this.pos = pos; } + public HeliFly(CPos pos) { this.pos = pos.CenterPosition; } + + public static bool AdjustAltitude(Actor self, Helicopter helicopter, WRange targetAltitude) { - Dest = dest; + var altitude = helicopter.CenterPosition.Z; + if (altitude == targetAltitude.Range) + return false; + + var delta = helicopter.Info.AltitudeVelocity.Range; + var dz = (targetAltitude.Range - altitude).Clamp(-delta, delta); + helicopter.SetPosition(self, helicopter.CenterPosition + new WVec(0, 0, dz)); + + return true; } public override Activity Tick(Actor self) { - if (IsCanceled) return NextActivity; + if (IsCanceled) + return NextActivity; - var info = self.Info.Traits.Get(); - var aircraft = self.Trait(); + var helicopter = self.Trait(); - if (aircraft.Altitude != info.CruiseAltitude) - { - aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude); + var cruiseAltitude = new WRange(helicopter.Info.CruiseAltitude * 1024 / Game.CellSize); + if (HeliFly.AdjustAltitude(self, helicopter, cruiseAltitude)) return this; - } - var dist = Dest - aircraft.PxPosition; - if (Math.Abs(dist.X) < 2 && Math.Abs(dist.Y) < 2) + // Rotate towards the target + var dist = pos - self.CenterPosition; + var desiredFacing = Util.GetFacing(dist, helicopter.Facing); + helicopter.Facing = Util.TickFacing(helicopter.Facing, desiredFacing, helicopter.ROT); + + // The next move would overshoot, so just set the final position + var move = helicopter.FlyStep(desiredFacing); + if (dist.HorizontalLengthSquared < move.HorizontalLengthSquared) { - aircraft.SubPxPosition = Dest.ToPSubPos(); + helicopter.SetPosition(self, pos + new WVec(0, 0, cruiseAltitude.Range - pos.Z)); return NextActivity; } - var desiredFacing = Util.GetFacing(dist, aircraft.Facing); - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); - aircraft.TickMove( PSubPos.PerPx * aircraft.MovementSpeed, desiredFacing ); + helicopter.SetPosition(self, helicopter.CenterPosition + move); return this; } - public override IEnumerable GetTargets( Actor self ) + public override IEnumerable GetTargets(Actor self) { - yield return Target.FromPos(Dest); + yield return Target.FromPos(pos); } } } diff --git a/OpenRA.Mods.RA/Air/HeliLand.cs b/OpenRA.Mods.RA/Air/HeliLand.cs index 00479cae7a..0842b7201f 100755 --- a/OpenRA.Mods.RA/Air/HeliLand.cs +++ b/OpenRA.Mods.RA/Air/HeliLand.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -14,27 +14,27 @@ namespace OpenRA.Mods.RA.Air { class HeliLand : Activity { - public HeliLand(bool requireSpace, int minimalAltitude) + bool requireSpace; + + public HeliLand(bool requireSpace) { this.requireSpace = requireSpace; - this.minimalAltitude = minimalAltitude; } - bool requireSpace; - int minimalAltitude = 0; - public override Activity Tick(Actor self) { - if (IsCanceled) return NextActivity; - var aircraft = self.Trait(); - if (aircraft.Altitude == minimalAltitude) + if (IsCanceled) return NextActivity; - if (requireSpace && !aircraft.CanLand(self.Location)) + var helicopter = self.Trait(); + + if (requireSpace && !helicopter.CanLand(self.Location)) return this; - --aircraft.Altitude; - return this; + if (HeliFly.AdjustAltitude(self, helicopter, helicopter.Info.LandAltitude)) + return this; + + return NextActivity; } } } diff --git a/OpenRA.Mods.RA/Air/HeliReturn.cs b/OpenRA.Mods.RA/Air/HeliReturn.cs index 6481786ca5..5b11319df0 100755 --- a/OpenRA.Mods.RA/Air/HeliReturn.cs +++ b/OpenRA.Mods.RA/Air/HeliReturn.cs @@ -1,6 +1,6 @@ -#region Copyright & License Information +#region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -9,8 +9,8 @@ #endregion using System.Linq; -using OpenRA.Traits; using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; namespace OpenRA.Mods.RA.Air { @@ -19,16 +19,16 @@ namespace OpenRA.Mods.RA.Air static Actor ChooseHelipad(Actor self) { var rearmBuildings = self.Info.Traits.Get().RearmBuildings; - return self.World.Actors.Where( a => a.Owner == self.Owner ).FirstOrDefault( - a => rearmBuildings.Contains(a.Info.Name) && - !Reservable.IsReserved(a)); + return self.World.Actors.Where(a => a.Owner == self.Owner).FirstOrDefault( + a => rearmBuildings.Contains(a.Info.Name) && !Reservable.IsReserved(a)); } public override Activity Tick(Actor self) { - if (IsCanceled) return NextActivity; - var dest = ChooseHelipad(self); + if (IsCanceled) + return NextActivity; + var dest = ChooseHelipad(self); var initialFacing = self.Info.Traits.Get().InitialFacing; if (dest == null) @@ -40,23 +40,23 @@ namespace OpenRA.Mods.RA.Air .ClosestTo(self); if (nearestHpad == null) - return Util.SequenceActivities(new Turn(initialFacing), new HeliLand(true, 0), NextActivity); + return Util.SequenceActivities(new Turn(initialFacing), new HeliLand(true), NextActivity); else - return Util.SequenceActivities(new HeliFly(Util.CenterOfCell(nearestHpad.Location))); + return Util.SequenceActivities(new HeliFly(nearestHpad.CenterPosition)); } var res = dest.TraitOrDefault(); var heli = self.Trait(); if (res != null) - heli.reservation = res.Reserve(dest, self, heli); + heli.Reservation = res.Reserve(dest, self, heli); var exit = dest.Info.Traits.WithInterface().FirstOrDefault(); - var offset = exit != null ? exit.SpawnOffsetVector : PVecInt.Zero; + var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero; return Util.SequenceActivities( - new HeliFly(dest.Trait().PxPosition + offset), + new HeliFly(dest.CenterPosition + offset), new Turn(initialFacing), - new HeliLand(false, 0), + new HeliLand(false), new Rearm(self), NextActivity); } diff --git a/OpenRA.Mods.RA/Air/Helicopter.cs b/OpenRA.Mods.RA/Air/Helicopter.cs index 103dfb971f..33c5a2d89e 100755 --- a/OpenRA.Mods.RA/Air/Helicopter.cs +++ b/OpenRA.Mods.RA/Air/Helicopter.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -17,29 +17,31 @@ namespace OpenRA.Mods.RA.Air { class HelicopterInfo : AircraftInfo { - public readonly int IdealSeparation = 40; + public readonly WRange IdealSeparation = new WRange(1706); public readonly bool LandWhenIdle = true; - public readonly int MinimalLandAltitude = 0; + public readonly WRange LandAltitude = WRange.Zero; + public readonly WRange AltitudeVelocity = new WRange(43); - public override object Create( ActorInitializer init ) { return new Helicopter( init, this); } + public override object Create(ActorInitializer init) { return new Helicopter(init, this); } } class Helicopter : Aircraft, ITick, IResolveOrder { - HelicopterInfo Info; + public HelicopterInfo Info; bool firstTick = true; - public Helicopter( ActorInitializer init, HelicopterInfo info) : base( init, info ) + public Helicopter(ActorInitializer init, HelicopterInfo info) + : base(init, info) { Info = info; } public void ResolveOrder(Actor self, Order order) { - if (reservation != null) + if (Reservation != null) { - reservation.Dispose(); - reservation = null; + Reservation.Dispose(); + Reservation = null; } if (order.OrderString == "Move") @@ -48,12 +50,12 @@ namespace OpenRA.Mods.RA.Air self.SetTargetLine(Target.FromCell(target), Color.Green); self.CancelActivity(); - self.QueueActivity(new HeliFly(Util.CenterOfCell(target))); + self.QueueActivity(new HeliFly(target)); if (Info.LandWhenIdle) { self.QueueActivity(new Turn(Info.InitialFacing)); - self.QueueActivity(new HeliLand(true, Info.MinimalLandAltitude)); + self.QueueActivity(new HeliLand(true)); } } @@ -68,17 +70,17 @@ namespace OpenRA.Mods.RA.Air { var res = order.TargetActor.TraitOrDefault(); if (res != null) - reservation = res.Reserve(order.TargetActor, self, this); + Reservation = res.Reserve(order.TargetActor, self, this); var exit = order.TargetActor.Info.Traits.WithInterface().FirstOrDefault(); - var offset = exit != null ? exit.SpawnOffsetVector : PVecInt.Zero; + var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero; self.SetTargetLine(Target.FromActor(order.TargetActor), Color.Green); self.CancelActivity(); - self.QueueActivity(new HeliFly(order.TargetActor.Trait().PxPosition + offset)); + self.QueueActivity(new HeliFly(order.TargetActor.CenterPosition + offset)); self.QueueActivity(new Turn(Info.InitialFacing)); - self.QueueActivity(new HeliLand(false, Info.MinimalLandAltitude)); + self.QueueActivity(new HeliLand(false)); self.QueueActivity(new ResupplyAircraft()); } } @@ -86,7 +88,7 @@ namespace OpenRA.Mods.RA.Air if (order.OrderString == "ReturnToBase") { self.CancelActivity(); - self.QueueActivity( new HeliReturn() ); + self.QueueActivity(new HeliReturn()); } if (order.OrderString == "Stop") @@ -96,7 +98,7 @@ namespace OpenRA.Mods.RA.Air if (Info.LandWhenIdle) { self.QueueActivity(new Turn(Info.InitialFacing)); - self.QueueActivity(new HeliLand(true, Info.MinimalLandAltitude)); + self.QueueActivity(new HeliLand(true)); } } } @@ -110,38 +112,42 @@ namespace OpenRA.Mods.RA.Air ReserveSpawnBuilding(); } - /* repulsion only applies when we're flying */ - if (Altitude <= 0) return; + // Repulsion only applies when we're flying! + var altitude = CenterPosition.Z; + var cruiseAltitude = Info.CruiseAltitude * 1024 / Game.CellSize; + if (altitude != cruiseAltitude) + return; - var separation = new WRange(Info.IdealSeparation * 1024 / Game.CellSize); - var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, separation) + var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation) .Where(a => a.HasTrait()); var f = otherHelis .Select(h => GetRepulseForce(self, h)) - .Aggregate(PSubVec.Zero, (a, b) => a + b); + .Aggregate(WVec.Zero, (a, b) => a + b); - // FIXME(jsd): not sure which units GetFacing accepts; code is unclear to me. - int repulsionFacing = Util.GetFacing( f.ToInt2(), -1 ); - if( repulsionFacing != -1 ) - TickMove(PSubPos.PerPx * MovementSpeed, repulsionFacing); + int repulsionFacing = Util.GetFacing(f, -1); + if (repulsionFacing != -1) + SetPosition(self, CenterPosition + FlyStep(repulsionFacing)); } - // Returns a vector in subPx units - public PSubVec GetRepulseForce(Actor self, Actor h) + public WVec GetRepulseForce(Actor self, Actor other) { - if (self == h) - return PSubVec.Zero; - if( h.Trait().Altitude < Altitude ) - return PSubVec.Zero; - var d = self.CenterLocation - h.CenterLocation; + if (self == other || other.CenterPosition.Z < self.CenterPosition.Z) + return WVec.Zero; - if (d.Length > Info.IdealSeparation) - return PSubVec.Zero; + var d = self.CenterPosition - other.CenterPosition; + var distSq = d.HorizontalLengthSquared; + if (distSq > Info.IdealSeparation.Range * Info.IdealSeparation.Range) + return WVec.Zero; - if (d.LengthSquared < 1) - return Util.SubPxVector[self.World.SharedRandom.Next(255)]; - return (5 * d.ToPSubVec()) / d.LengthSquared; + if (distSq < 1) + { + var yaw = self.World.SharedRandom.Next(0, 1023); + var rot = new WRot(WAngle.Zero, WAngle.Zero, new WAngle(yaw)); + return new WVec(1024, 0, 0).Rotate(rot); + } + + return (d * 1024 * 8) / (int)distSq; } } } diff --git a/OpenRA.Mods.RA/Air/Land.cs b/OpenRA.Mods.RA/Air/Land.cs index eb5d41f398..d6bde50f44 100755 --- a/OpenRA.Mods.RA/Air/Land.cs +++ b/OpenRA.Mods.RA/Air/Land.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -16,29 +16,31 @@ namespace OpenRA.Mods.RA.Air { public class Land : Activity { - Target Target; + Target target; - public Land(Target t) { Target = t; } + public Land(Target t) { target = t; } public override Activity Tick(Actor self) { - if (!Target.IsValid) + if (!target.IsValid) Cancel(self); - if (IsCanceled) return NextActivity; - - var d = Target.CenterPosition - self.CenterPosition; - if (d.LengthSquared < 256*256) // close enough (1/4 cell) + if (IsCanceled) return NextActivity; - var aircraft = self.Trait(); + var plane = self.Trait(); + var d = target.CenterPosition - self.CenterPosition; - if (aircraft.Altitude > 0) - --aircraft.Altitude; + // The next move would overshoot, so just set the final position + var move = plane.FlyStep(plane.Facing); + if (d.HorizontalLengthSquared < move.HorizontalLengthSquared) + { + plane.SetPosition(self, target.CenterPosition); + return NextActivity; + } - var desiredFacing = Util.GetFacing(d, aircraft.Facing); - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); - aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, aircraft.Facing); + var desiredFacing = Util.GetFacing(d, plane.Facing); + Fly.FlyToward(self, plane, desiredFacing, WRange.Zero); return this; } diff --git a/OpenRA.Mods.RA/Air/Plane.cs b/OpenRA.Mods.RA/Air/Plane.cs index 6a877be1ed..9c90191f72 100755 --- a/OpenRA.Mods.RA/Air/Plane.cs +++ b/OpenRA.Mods.RA/Air/Plane.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -16,15 +16,21 @@ namespace OpenRA.Mods.RA.Air { public class PlaneInfo : AircraftInfo { - public override object Create( ActorInitializer init ) { return new Plane( init, this ); } + public readonly WAngle MaximumPitch = WAngle.FromDegrees(10); + + public override object Create(ActorInitializer init) { return new Plane(init, this); } } public class Plane : Aircraft, IResolveOrder, ITick, ISync { - [Sync] public PVecInt RTBPathHash; + public readonly PlaneInfo Info; + [Sync] public WPos RTBPathHash; - public Plane( ActorInitializer init, PlaneInfo info ) - : base( init, info ) { } + public Plane(ActorInitializer init, PlaneInfo info) + : base(init, info) + { + Info = info; + } bool firstTick = true; public void Tick(Actor self) @@ -49,7 +55,6 @@ namespace OpenRA.Mods.RA.Air self.QueueActivity(Fly.ToCell(target)); self.QueueActivity(new FlyCircle()); } - else if (order.OrderString == "Enter") { if (Reservable.IsReserved(order.TargetActor)) return; diff --git a/OpenRA.Mods.RA/Air/ReturnOnIdle.cs b/OpenRA.Mods.RA/Air/ReturnOnIdle.cs index ee643df58c..3b9ca48beb 100755 --- a/OpenRA.Mods.RA/Air/ReturnOnIdle.cs +++ b/OpenRA.Mods.RA/Air/ReturnOnIdle.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -17,14 +17,13 @@ namespace OpenRA.Mods.RA.Air { class ReturnOnIdleInfo : TraitInfo { } - // fly home or fly-off-map behavior for idle planes - class ReturnOnIdle : INotifyIdle { public void TickIdle(Actor self) { - var altitude = self.Trait().Altitude; - if (altitude == 0) return; // we're on the ground, let's stay there. + // We're on the ground, let's stay there. + if (self.CenterPosition.Z == 0) + return; var airfield = ReturnToBase.ChooseAirfield(self, true); if (airfield != null) @@ -38,13 +37,13 @@ namespace OpenRA.Mods.RA.Air // i'd prefer something we own var someBuilding = self.World.ActorsWithTrait() - .Select( a => a.Actor ) + .Select(a => a.Actor) .FirstOrDefault(a => a.Owner == self.Owner); // failing that, something unlikely to shoot at us if (someBuilding == null) someBuilding = self.World.ActorsWithTrait() - .Select( a => a.Actor ) + .Select(a => a.Actor) .FirstOrDefault(a => self.Owner.Stances[a.Owner] == Stance.Ally); if (someBuilding == null) diff --git a/OpenRA.Mods.RA/Air/ReturnToBase.cs b/OpenRA.Mods.RA/Air/ReturnToBase.cs index 22a06df9b7..0d19cb48f5 100755 --- a/OpenRA.Mods.RA/Air/ReturnToBase.cs +++ b/OpenRA.Mods.RA/Air/ReturnToBase.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -10,8 +10,8 @@ using System; using System.Linq; -using OpenRA.Traits; using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; namespace OpenRA.Mods.RA.Air { @@ -19,8 +19,7 @@ namespace OpenRA.Mods.RA.Air { bool isCalculated; Actor dest; - - PPos w1, w2, w3; /* tangent points to turn circles */ + WPos w1, w2, w3; public static Actor ChooseAirfield(Actor self, bool unreservedOnly) { @@ -35,53 +34,60 @@ namespace OpenRA.Mods.RA.Air void Calculate(Actor self) { - if (dest == null || Reservable.IsReserved(dest)) dest = ChooseAirfield(self, true); + if (dest == null || Reservable.IsReserved(dest)) + dest = ChooseAirfield(self, true); - if (dest == null) return; + if (dest == null) + return; var plane = self.Trait(); + var planeInfo = self.Info.Traits.Get(); var res = dest.TraitOrDefault(); if (res != null) { plane.UnReserve(); - plane.reservation = res.Reserve(dest, self, plane); + plane.Reservation = res.Reserve(dest, self, plane); } - var landPos = dest.CenterLocation; - var aircraft = self.Trait(); + var landPos = dest.CenterPosition; - var speed = .2f * aircraft.MovementSpeed; + // Distance required for descent. + var landDistance = planeInfo.CruiseAltitude * 1024 * 1024 / (Game.CellSize * plane.Info.MaximumPitch.Tan()); + var altitude = planeInfo.CruiseAltitude * 1024 / Game.CellSize; - /* if the aircraft is on the ground, it will take off to the cruise altitude first before approaching */ - var altitude = aircraft.Altitude; - if (altitude == 0) altitude = self.Info.Traits.Get().CruiseAltitude; + // Land towards the east + var approachStart = landPos + new WVec(-landDistance, 0, altitude); - var approachStart = landPos.ToInt2() - new float2(altitude * speed, 0); - var turnRadius = (128f / self.Info.Traits.Get().ROT) * speed / (float)Math.PI; + // Add 10% to the turning radius to ensure we have enough room + var speed = plane.MovementSpeed * 1024 / (Game.CellSize * 5); + var turnRadius = (int)(141 * speed / planeInfo.ROT / (float)Math.PI); - /* work out the center points */ - var fwd = -float2.FromAngle(aircraft.Facing / 128f * (float)Math.PI); - var side = new float2(-fwd.Y, fwd.X); /* rotate */ + // Find the center of the turning circles for clockwise and counterclockwise turns + var angle = WAngle.FromFacing(plane.Facing); + var fwd = -new WVec(angle.Sin(), angle.Cos(), 0); + + // Work out whether we should turn clockwise or counter-clockwise for approach + var side = new WVec(-fwd.Y, fwd.X, fwd.Z); + var approachDelta = self.CenterPosition - approachStart; var sideTowardBase = new[] { side, -side } - .OrderBy(a => float2.Dot(a, self.CenterLocation.ToInt2() - approachStart)) + .OrderBy(a => WVec.Dot(a, approachDelta)) .First(); - var c1 = self.CenterLocation.ToInt2() + turnRadius * sideTowardBase; - var c2 = approachStart + new float2(0, turnRadius * Math.Sign(self.CenterLocation.Y - approachStart.Y)); // above or below start point + // Calculate the tangent line that joins the turning circles at the current and approach positions + var cp = self.CenterPosition + turnRadius * sideTowardBase / 1024; + var posCenter = new WPos(cp.X, cp.Y, altitude); + var approachCenter = approachStart + new WVec(0, turnRadius * Math.Sign(self.CenterPosition.Y - approachStart.Y), 0); + var tangentDirection = approachCenter - posCenter; + var tangentOffset = new WVec(-tangentDirection.Y, tangentDirection.X, 0) * turnRadius / tangentDirection.Length; - /* work out tangent points */ - var d = c2 - c1; - var e = (turnRadius / d.Length) * d; - var f = new float2(-e.Y, e.X); /* rotate */ + // TODO: correctly handle CCW <-> CW turns + if (tangentOffset.X > 0) + tangentOffset = -tangentOffset; - /* TODO: support internal tangents, too! */ - - if (f.X > 0) f = -f; - - w1 = (PPos)(c1 + f).ToInt2(); - w2 = (PPos)(c2 + f).ToInt2(); - w3 = (PPos)(approachStart).ToInt2(); - plane.RTBPathHash = (PVecInt)w1 + (PVecInt)w2 + (PVecInt)w3; + w1 = posCenter + tangentOffset; + w2 = approachCenter + tangentOffset; + w3 = approachStart; + plane.RTBPathHash = w1 + (WVec)w2 + (WVec)w3; isCalculated = true; } @@ -93,12 +99,12 @@ namespace OpenRA.Mods.RA.Air public override Activity Tick(Actor self) { - if (IsCanceled) - return NextActivity; - if (self.IsDead()) + if (IsCanceled || self.IsDead()) return NextActivity; + if (!isCalculated) Calculate(self); + if (dest == null) { var nearestAfld = ChooseAirfield(self, false); @@ -111,9 +117,9 @@ namespace OpenRA.Mods.RA.Air } return Util.SequenceActivities( - Fly.ToPx(w1), - Fly.ToPx(w2), - Fly.ToPx(w3), + Fly.ToPos(w1), + Fly.ToPos(w2), + Fly.ToPos(w3), new Land(Target.FromActor(dest)), NextActivity); } diff --git a/OpenRA.Mods.RA/Air/TargetableAircraft.cs b/OpenRA.Mods.RA/Air/TargetableAircraft.cs index 49bcd2ffd8..0cbeb27e41 100755 --- a/OpenRA.Mods.RA/Air/TargetableAircraft.cs +++ b/OpenRA.Mods.RA/Air/TargetableAircraft.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -9,13 +9,13 @@ #endregion using System.Drawing; -using OpenRA.Graphics; using System.Linq; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA.Air { - public class TargetableAircraftInfo : TargetableUnitInfo, Requires + public class TargetableAircraftInfo : TargetableUnitInfo { public readonly string[] GroundedTargetTypes = { }; public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); } @@ -24,19 +24,19 @@ namespace OpenRA.Mods.RA.Air public class TargetableAircraft : TargetableUnit { readonly TargetableAircraftInfo info; - readonly Aircraft Aircraft; + readonly Actor self; public TargetableAircraft(Actor self, TargetableAircraftInfo info) : base(self, info) { this.info = info; - Aircraft = self.Trait(); + this.self = self; } public override string[] TargetTypes { - get { return (Aircraft.Altitude > 0) ? info.TargetTypes - : info.GroundedTargetTypes; } + get { return (self.CenterPosition.Z > 0) ? info.TargetTypes + : info.GroundedTargetTypes; } } } } diff --git a/OpenRA.Mods.RA/Armament.cs b/OpenRA.Mods.RA/Armament.cs index e1b09e3e79..7eb5faf061 100755 --- a/OpenRA.Mods.RA/Armament.cs +++ b/OpenRA.Mods.RA/Armament.cs @@ -99,7 +99,7 @@ namespace OpenRA.Mods.RA // Note: facing is only used by the legacy positioning code // The world coordinate model uses Actor.Orientation - public void CheckFire(Actor self, AttackBase attack, IMove move, IFacing facing, Target target) + public void CheckFire(Actor self, AttackBase attack, IFacing facing, Target target) { if (FireDelay > 0) return; @@ -120,8 +120,6 @@ namespace OpenRA.Mods.RA return; var barrel = Barrels[Burst % Barrels.Length]; - var destMove = target.IsActor ? target.Actor.TraitOrDefault() : null; - var muzzlePosition = self.CenterPosition + MuzzleOffset(self, barrel); var legacyMuzzlePosition = PPos.FromWPos(muzzlePosition); var legacyMuzzleAltitude = Game.CellSize*muzzlePosition.Z/1024; @@ -135,8 +133,8 @@ namespace OpenRA.Mods.RA src = legacyMuzzlePosition, srcAltitude = legacyMuzzleAltitude, - dest = target.CenterLocation, - destAltitude = destMove != null ? destMove.Altitude : 0, + dest = PPos.FromWPos(target.CenterPosition), + destAltitude = target.CenterPosition.Z * Game.CellSize / 1024, facing = legacyFacing, diff --git a/OpenRA.Mods.RA/Attack/AttackBase.cs b/OpenRA.Mods.RA/Attack/AttackBase.cs index c8263c6dec..9321698c67 100644 --- a/OpenRA.Mods.RA/Attack/AttackBase.cs +++ b/OpenRA.Mods.RA/Attack/AttackBase.cs @@ -89,12 +89,12 @@ namespace OpenRA.Mods.RA public virtual void DoAttack(Actor self, Target target) { - if( !CanAttack( self, target ) ) return; + if (!CanAttack(self, target)) + return; - var move = self.TraitOrDefault(); var facing = self.TraitOrDefault(); foreach (var a in Armaments) - a.CheckFire(self, this, move, facing, target); + a.CheckFire(self, this, facing, target); } public IEnumerable Orders diff --git a/OpenRA.Mods.RA/Attack/AttackLoyalty.cs b/OpenRA.Mods.RA/Attack/AttackLoyalty.cs index ceb8caab0f..e7f7d64c83 100644 --- a/OpenRA.Mods.RA/Attack/AttackLoyalty.cs +++ b/OpenRA.Mods.RA/Attack/AttackLoyalty.cs @@ -38,10 +38,9 @@ namespace OpenRA.Mods.RA if (!target.IsInRange(self.CenterPosition, range)) return; - var move = self.TraitOrDefault(); var facing = self.TraitOrDefault(); foreach (var a in Armaments) - a.CheckFire(self, this, move, facing, target); + a.CheckFire(self, this, facing, target); if (target.Actor != null) target.Actor.ChangeOwner(self.Owner); diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index ea51b80d62..ec2d7545f0 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -158,7 +158,7 @@ namespace OpenRA.Mods.RA { foreach (var c in TileSprites[currentTemplate].Keys) foreach (var a in self.World.ActorMap.GetUnitsAt(c)) - if (a.HasTrait() && !a.Trait().CanEnterCell(c)) + if (a.HasTrait() && !a.Trait().CanEnterCell(c)) a.Kill(self); } diff --git a/OpenRA.Mods.RA/Buildings/Building.cs b/OpenRA.Mods.RA/Buildings/Building.cs index 057523555e..ef99c3eb38 100755 --- a/OpenRA.Mods.RA/Buildings/Building.cs +++ b/OpenRA.Mods.RA/Buildings/Building.cs @@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA.Buildings public class GivesBuildableAreaInfo : TraitInfo {} public class GivesBuildableArea {} - public class BuildingInfo : ITraitInfo, UsesInit + public class BuildingInfo : ITraitInfo, IOccupySpaceInfo, UsesInit { [Desc("If negative, it will drain power, if positive, it will provide power.")] public readonly int Power = 0; @@ -96,7 +96,6 @@ namespace OpenRA.Mods.RA.Buildings [Sync] readonly CPos topLeft; PowerManager PlayerPower; - PPos pxPosition; [Sync] public bool Locked; /* shared activity lock: undeploy, sell, capture, etc */ @@ -110,7 +109,7 @@ namespace OpenRA.Mods.RA.Buildings public void Unlock() { Locked = false; } public CPos TopLeft { get { return topLeft; } } - public PPos PxPosition { get { return pxPosition; } } + public WPos CenterPosition { get; private set; } public IEnumerable ProvidesPrerequisites { get { yield return self.Info.Name; } } @@ -124,8 +123,7 @@ namespace OpenRA.Mods.RA.Buildings occupiedCells = FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft ) .Select(c => Pair.New(c, SubCell.FullCell)).ToArray(); - var position = topLeft.CenterPosition + FootprintUtils.CenterOffset(Info); - pxPosition = PPos.FromWPosHackZ(position); + CenterPosition = topLeft.CenterPosition + FootprintUtils.CenterOffset(Info); } public int GetPowerUsage() diff --git a/OpenRA.Mods.RA/Cargo.cs b/OpenRA.Mods.RA/Cargo.cs index 4223a6c57d..a9add822c1 100644 --- a/OpenRA.Mods.RA/Cargo.cs +++ b/OpenRA.Mods.RA/Cargo.cs @@ -17,14 +17,14 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - public class CargoInfo : ITraitInfo + public class CargoInfo : ITraitInfo, Requires { public readonly int MaxWeight = 0; public readonly int PipCount = 0; public readonly string[] Types = { }; public readonly int UnloadFacing = 0; public readonly string[] InitialUnits = { }; - public readonly int minimalUnloadAltitude = 0; + public readonly WRange MaximumUnloadAltitude = WRange.Zero; public object Create( ActorInitializer init ) { return new Cargo( init, this ); } } @@ -92,8 +92,8 @@ namespace OpenRA.Mods.RA return false; // Cannot unload mid-air - var move = self.TraitOrDefault(); - if (move != null && move.Altitude > info.minimalUnloadAltitude) + var ios = self.TraitOrDefault(); + if (ios != null && ios.CenterPosition.Z > info.MaximumUnloadAltitude.Range) return false; // TODO: Check if there is a free tile to unload to @@ -106,8 +106,7 @@ namespace OpenRA.Mods.RA return false; // Cannot load mid-air - var move = self.TraitOrDefault(); - return move == null || move.Altitude == info.minimalUnloadAltitude; + return self.CenterPosition.Z <= info.MaximumUnloadAltitude.Range; } public string CursorForOrder(Actor self, Order order) diff --git a/OpenRA.Mods.RA/CarpetBomb.cs b/OpenRA.Mods.RA/CarpetBomb.cs index 80148646a6..13a40c98ae 100644 --- a/OpenRA.Mods.RA/CarpetBomb.cs +++ b/OpenRA.Mods.RA/CarpetBomb.cs @@ -56,12 +56,14 @@ namespace OpenRA.Mods.RA var weapon = Rules.Weapons[info.Weapon.ToLowerInvariant()]; dropDelay = weapon.ROF; + var centerLocation = PPos.FromWPos(self.CenterPosition); + var altitude = self.CenterPosition.Z * Game.CellSize / 1024; var args = new ProjectileArgs { - srcAltitude = self.Trait().Altitude, + srcAltitude = altitude, destAltitude = 0, - src = self.CenterLocation, - dest = self.CenterLocation, + src = centerLocation, + dest = centerLocation, facing = self.Trait().Facing, firedBy = self, weapon = weapon diff --git a/OpenRA.Mods.RA/ChronoshiftDeploy.cs b/OpenRA.Mods.RA/ChronoshiftDeploy.cs index 36fc932535..0a6c5bb7a6 100644 --- a/OpenRA.Mods.RA/ChronoshiftDeploy.cs +++ b/OpenRA.Mods.RA/ChronoshiftDeploy.cs @@ -94,7 +94,7 @@ namespace OpenRA.Mods.RA public bool CanJumpTo(CPos xy, bool ignoreVis) { - var movement = self.TraitOrDefault(); + var movement = self.TraitOrDefault(); if (chargeTick <= 0 // Can jump && (self.Location - xy).Length <= Info.JumpDistance // Within jump range diff --git a/OpenRA.Mods.RA/Chronoshiftable.cs b/OpenRA.Mods.RA/Chronoshiftable.cs index 44e54bc9e4..da7311defe 100755 --- a/OpenRA.Mods.RA/Chronoshiftable.cs +++ b/OpenRA.Mods.RA/Chronoshiftable.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -9,6 +9,7 @@ #endregion using System.Drawing; +using OpenRA.FileFormats; using OpenRA.Mods.RA.Activities; using OpenRA.Traits; @@ -19,38 +20,43 @@ namespace OpenRA.Mods.RA public readonly bool ExplodeInstead = false; public readonly string ChronoshiftSound = "chrono2.aud"; - public object Create(ActorInitializer init) { return new Chronoshiftable(this); } + public object Create(ActorInitializer init) { return new Chronoshiftable(init, this); } } public class Chronoshiftable : ITick, ISync, ISelectionBar { - // Return-to-sender logic - [Sync] CPos chronoshiftOrigin; - [Sync] int chronoshiftReturnTicks = 0; + readonly ChronoshiftableInfo info; Actor chronosphere; bool killCargo; - int TotalTicks; - readonly ChronoshiftableInfo info; + int duration; - public Chronoshiftable(ChronoshiftableInfo info) + // Return-to-sender logic + [Sync] public CPos Origin; + [Sync] public int ReturnTicks = 0; + + public Chronoshiftable(ActorInitializer init, ChronoshiftableInfo info) { this.info = info; + + if (init.Contains()) + ReturnTicks = init.Get(); + + if (init.Contains()) + Origin = init.Get(); } public void Tick(Actor self) { - if (chronoshiftReturnTicks <= 0) + if (ReturnTicks <= 0) return; - if (chronoshiftReturnTicks > 0) - chronoshiftReturnTicks--; - // Return to original location - if (chronoshiftReturnTicks == 0) + if (--ReturnTicks == 0) { self.CancelActivity(); + // TODO: need a new Teleport method that will move to the closest available cell - self.QueueActivity(new Teleport(chronosphere, chronoshiftOrigin, killCargo, info.ChronoshiftSound)); + self.QueueActivity(new Teleport(chronosphere, Origin, killCargo, info.ChronoshiftSound)); } } @@ -58,25 +64,27 @@ namespace OpenRA.Mods.RA public virtual bool CanChronoshiftTo(Actor self, CPos targetLocation) { // TODO: Allow enemy units to be chronoshifted into bad terrain to kill them - return (self.HasTrait() && self.Trait().CanEnterCell(targetLocation)); + return self.HasTrait() && self.Trait().CanEnterCell(targetLocation); } public virtual bool Teleport(Actor self, CPos targetLocation, int duration, bool killCargo, Actor chronosphere) { - if (info.ExplodeInstead) // some things appear chronoshiftable, but instead they just die. + // some things appear chronoshiftable, but instead they just die. + if (info.ExplodeInstead) { self.World.AddFrameEndTask(w => { // damage is inflicted by the chronosphere - if (!self.Destroyed) self.InflictDamage(chronosphere, int.MaxValue, null); + if (!self.Destroyed) + self.InflictDamage(chronosphere, int.MaxValue, null); }); return true; } /// Set up return-to-sender info - chronoshiftOrigin = self.Location; - chronoshiftReturnTicks = duration; - TotalTicks = duration; + Origin = self.Location; + ReturnTicks = duration; + this.duration = duration; this.chronosphere = chronosphere; this.killCargo = killCargo; @@ -90,11 +98,27 @@ namespace OpenRA.Mods.RA // Show the remaining time as a bar public float GetValue() { - if (chronoshiftReturnTicks == 0) // otherwise an empty bar is rendered all the time + if (ReturnTicks == 0) // otherwise an empty bar is rendered all the time return 0f; - return (float)chronoshiftReturnTicks / TotalTicks; + return (float)ReturnTicks / duration; } + public Color GetColor() { return Color.White; } } + + public class ChronoshiftReturnInit : IActorInit + { + [FieldFromYamlKey] readonly int value = 0; + public ChronoshiftReturnInit() { } + public ChronoshiftReturnInit(int init) { value = init; } + public int Value(World world) { return value; } + } + + public class ChronoshiftOriginInit : IActorInit + { + [FieldFromYamlKey] readonly CPos value; + public ChronoshiftOriginInit(CPos init) { value = init; } + public CPos Value(World world) { return value; } + } } diff --git a/OpenRA.Mods.RA/Crate.cs b/OpenRA.Mods.RA/Crate.cs index e1a2c87041..b1ab283250 100644 --- a/OpenRA.Mods.RA/Crate.cs +++ b/OpenRA.Mods.RA/Crate.cs @@ -11,12 +11,12 @@ using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; -using OpenRA.Traits; using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; namespace OpenRA.Mods.RA { - class CrateInfo : ITraitInfo, Requires + class CrateInfo : ITraitInfo, IOccupySpaceInfo, Requires { public readonly int Lifetime = 5; // Seconds public readonly string[] TerrainTypes = { }; @@ -24,26 +24,25 @@ namespace OpenRA.Mods.RA } // ITeleportable is required for paradrop - class Crate : ITick, IOccupySpace, ITeleportable, ICrushable, ISync, INotifyParachuteLanded + class Crate : ITick, IPositionable, ICrushable, ISync, INotifyParachuteLanded { readonly Actor self; + readonly CrateInfo info; + bool collected; + [Sync] int ticks; [Sync] public CPos Location; - CrateInfo Info; - bool collected; public Crate(ActorInitializer init, CrateInfo info) { this.self = init.self; + this.info = info; + if (init.Contains()) - { - this.Location = init.Get(); - PxPosition = Util.CenterOfCell(Location); - } - this.Info = info; + SetPosition(self, init.Get()); } - public void WarnCrush(Actor crusher) {} + public void WarnCrush(Actor crusher) { } public void OnCrush(Actor crusher) { @@ -78,27 +77,22 @@ namespace OpenRA.Mods.RA public void Tick(Actor self) { - if( ++ticks >= Info.Lifetime * 25 ) + if (++ticks >= info.Lifetime * 25) self.Destroy(); } public CPos TopLeft { get { return Location; } } - public IEnumerable> OccupiedCells() { yield return Pair.New( Location, SubCell.FullCell); } + public IEnumerable> OccupiedCells() { yield return Pair.New(Location, SubCell.FullCell); } - public PPos PxPosition { get; private set; } - - public void SetPxPosition(Actor self, PPos px) - { - SetPosition( self, px.ToCPos() ); - } - - public void AdjustPxPosition(Actor self, PPos px) { SetPxPosition(self, px); } + public WPos CenterPosition { get; private set; } + public void SetPosition(Actor self, WPos pos) { SetPosition(self, pos.ToCPos()); } + public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos.ToCPos()); } public bool CanEnterCell(CPos cell) { if (!self.World.Map.IsInMap(cell.X, cell.Y)) return false; var type = self.World.GetTerrainType(cell); - if (!Info.TerrainTypes.Contains(type)) + if (!info.TerrainTypes.Contains(type)) return false; if (self.World.WorldActor.Trait().GetBuildingAt(cell) != null) return false; @@ -109,18 +103,18 @@ namespace OpenRA.Mods.RA public void SetPosition(Actor self, CPos cell) { - if( self.IsInWorld ) + if (self.IsInWorld) self.World.ActorMap.Remove(self, this); Location = cell; - PxPosition = Util.CenterOfCell(cell); + CenterPosition = cell.CenterPosition; var seq = self.World.GetTerrainInfo(cell).IsWater ? "water" : "land"; var rs = self.Trait(); if (seq != rs.anim.CurrentSequence.Name) rs.anim.PlayRepeating(seq); - if( self.IsInWorld ) + if (self.IsInWorld) self.World.ActorMap.Add(self, this); } diff --git a/OpenRA.Mods.RA/Effects/Missile.cs b/OpenRA.Mods.RA/Effects/Missile.cs index 6b3aea3198..7eae2bffdb 100755 --- a/OpenRA.Mods.RA/Effects/Missile.cs +++ b/OpenRA.Mods.RA/Effects/Missile.cs @@ -97,9 +97,9 @@ namespace OpenRA.Mods.RA.Effects // In pixels var dist = Args.target.CenterLocation + offset - PxPosition; - var targetAltitude = 0; - if (Args.target.IsValid && Args.target.IsActor && Args.target.Actor.HasTrait()) - targetAltitude = Args.target.Actor.Trait().Altitude; + var targetAltitude = 0; + if (Args.target.IsValid) + targetAltitude = Args.target.CenterPosition.Z * Game.CellSize / 1024; var jammed = Info.Jammable && world.ActorsWithTrait().Any(tp => (tp.Actor.CenterLocation - PxPosition).ToCVec().Length <= tp.Trait.Range diff --git a/OpenRA.Mods.RA/Effects/Parachute.cs b/OpenRA.Mods.RA/Effects/Parachute.cs index 9939f0f74a..8ebbf056e1 100644 --- a/OpenRA.Mods.RA/Effects/Parachute.cs +++ b/OpenRA.Mods.RA/Effects/Parachute.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA.Effects parachuteOffset = pai.Offset; // Adjust x,y to match the target subcell - cargo.Trait().SetPosition(cargo, dropPosition.ToCPos()); + cargo.Trait().SetPosition(cargo, dropPosition.ToCPos()); var cp = cargo.CenterPosition; pos = new WPos(cp.X, cp.Y, dropPosition.Z); } diff --git a/OpenRA.Mods.RA/Husk.cs b/OpenRA.Mods.RA/Husk.cs index 7c8a03c701..a46f577362 100644 --- a/OpenRA.Mods.RA/Husk.cs +++ b/OpenRA.Mods.RA/Husk.cs @@ -9,86 +9,78 @@ #endregion using System.Collections.Generic; +using System.Linq; using OpenRA.FileFormats; -using OpenRA.Traits; using OpenRA.Mods.RA.Move; +using OpenRA.Traits; namespace OpenRA.Mods.RA { - class HuskInfo : ITraitInfo, IFacingInfo + class HuskInfo : ITraitInfo, IOccupySpaceInfo, IFacingInfo { - public object Create( ActorInitializer init ) { return new Husk( init ); } + public readonly string[] AllowedTerrain = { }; + + public object Create(ActorInitializer init) { return new Husk(init, this); } public int GetInitialFacing() { return 128; } } - class Husk : IOccupySpace, IFacing, ISync + class Husk : IPositionable, IFacing, ISync { - [Sync] CPos location; - - [Sync] public PPos PxPosition { get; set; } + readonly HuskInfo info; + readonly Actor self; + [Sync] public CPos TopLeft { get; private set; } + [Sync] public WPos CenterPosition { get; private set; } [Sync] public int Facing { get; set; } + public int ROT { get { return 0; } } - public Husk(ActorInitializer init) + public Husk(ActorInitializer init, HuskInfo info) { - var self = init.self; - location = init.Get(); - PxPosition = init.Contains() ? init.Get() : Util.CenterOfCell(location); - Facing = init.Contains() ? init.Get() : 128; + this.info = info; + this.self = init.self; - var speed = init.Contains() ? init.Get() : 0; - if (speed > 0) - { - var to = Util.CenterOfCell(location); - var length = (int)((to - PxPosition).Length * 3 / speed); - self.QueueActivity(new DragHusk(PxPosition, to, length, this)); - } + TopLeft = init.Get(); + var ppos = init.Contains() ? init.Get() : Util.CenterOfCell(TopLeft); + CenterPosition = ppos.ToWPos(0); + Facing = init.Contains() ? init.Get() : 128; + + var speed = init.Contains() ? init.Get() : 0; + var distance = (TopLeft.CenterPosition - CenterPosition).Length; + if (speed > 0 && distance > 0) + self.QueueActivity(new Drag(CenterPosition, TopLeft.CenterPosition, distance / speed)); } - public CPos TopLeft { get { return location; } } - public IEnumerable> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } - - class DragHusk : Activity + public bool CanEnterCell(CPos cell) { - Husk husk; - PPos endLocation; - PPos startLocation; - int length; + if (!self.World.Map.IsInMap(cell.X, cell.Y)) + return false; - public DragHusk(PPos start, PPos end, int length, Husk husk) - { - startLocation = start; - endLocation = end; - this.length = length; - this.husk = husk; - } + if (!info.AllowedTerrain.Contains(self.World.GetTerrainType(cell))) + return false; - int ticks = 0; - public override Activity Tick( Actor self ) - { - if (ticks >= length || length <= 1) - { - husk.PxPosition = endLocation; - return NextActivity; - } + return !self.World.ActorMap.AnyUnitsAt(cell); + } - husk.PxPosition = PPos.Lerp(startLocation, endLocation, ticks++, length - 1); - return this; - } + public void SetPosition(Actor self, CPos cell) { SetPosition(self, cell.CenterPosition); } + public void SetVisualPosition(Actor self, WPos pos) { CenterPosition = pos; } - public override IEnumerable GetTargets( Actor self ) { yield break; } - public override void Cancel( Actor self ) { } + public void SetPosition(Actor self, WPos pos) + { + self.World.ActorMap.Remove(self, this); + CenterPosition = pos; + TopLeft = pos.ToCPos(); + self.World.ActorMap.Add(self, this); } } public class HuskSpeedInit : IActorInit { - [FieldFromYamlKey] public readonly int value = 0; + [FieldFromYamlKey] readonly int value = 0; public HuskSpeedInit() { } - public HuskSpeedInit( int init ) { value = init; } - public int Value( World world ) { return value; } + public HuskSpeedInit(int init) { value = init; } + public int Value(World world) { return value; } } } diff --git a/OpenRA.Mods.RA/LeavesHusk.cs b/OpenRA.Mods.RA/LeavesHusk.cs index 7b04b1d9c2..1fc3f91fe3 100644 --- a/OpenRA.Mods.RA/LeavesHusk.cs +++ b/OpenRA.Mods.RA/LeavesHusk.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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, @@ -21,16 +21,14 @@ namespace OpenRA.Mods.RA [ActorReference] public readonly string HuskActor = null; - public object Create( ActorInitializer init ) { return new LeavesHusk(this); } + public object Create(ActorInitializer init) { return new LeavesHusk(this); } } public class LeavesHusk : INotifyKilled { - LeavesHuskInfo Info; - public LeavesHusk(LeavesHuskInfo info) - { - Info = info; - } + LeavesHuskInfo info; + + public LeavesHusk(LeavesHuskInfo info) { this.info = info; } public void Killed(Actor self, AttackInfo e) { @@ -54,23 +52,30 @@ namespace OpenRA.Mods.RA var aircraft = self.TraitOrDefault(); if (aircraft != null) - td.Add(new AltitudeInit(aircraft.Altitude)); + td.Add(new AltitudeInit(aircraft.CenterPosition.Z * Game.CellSize / 1024)); var facing = self.TraitOrDefault(); if (facing != null) - td.Add(new FacingInit( facing.Facing )); + td.Add(new FacingInit(facing.Facing)); // TODO: This will only take the first turret if there are multiple // This isn't a problem with the current units, but may be a problem for mods var turreted = self.TraitsImplementing().FirstOrDefault(); if (turreted != null) - td.Add( new TurretFacingInit(turreted.turretFacing) ); + td.Add(new TurretFacingInit(turreted.turretFacing)); + + var chronoshiftable = self.TraitOrDefault(); + if (chronoshiftable != null && chronoshiftable.ReturnTicks > 0) + { + td.Add(new ChronoshiftOriginInit(chronoshiftable.Origin)); + td.Add(new ChronoshiftReturnInit(chronoshiftable.ReturnTicks)); + } var huskActor = self.TraitsImplementing() .Select(ihm => ihm.HuskActor(self)) .FirstOrDefault(a => a != null); - w.CreateActor(huskActor ?? Info.HuskActor, td); + w.CreateActor(huskActor ?? info.HuskActor, td); }); } } diff --git a/OpenRA.Mods.RA/Mine.cs b/OpenRA.Mods.RA/Mine.cs index 8d57909240..3c3ad8df31 100644 --- a/OpenRA.Mods.RA/Mine.cs +++ b/OpenRA.Mods.RA/Mine.cs @@ -17,7 +17,7 @@ using OpenRA.FileFormats; namespace OpenRA.Mods.RA { - class MineInfo : ITraitInfo + class MineInfo : ITraitInfo, IOccupySpaceInfo { public readonly string[] CrushClasses = { }; public readonly bool AvoidFriendly = true; @@ -61,7 +61,7 @@ namespace OpenRA.Mods.RA public CPos TopLeft { get { return location; } } public IEnumerable> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } - public PPos PxPosition { get { return Util.CenterOfCell( location ); } } + public WPos CenterPosition { get { return location.CenterPosition; } } } /* tag trait for stuff that shouldnt trigger mines */ diff --git a/OpenRA.Mods.RA/Minelayer.cs b/OpenRA.Mods.RA/Minelayer.cs index 6d638a0e0e..f6d25c367f 100644 --- a/OpenRA.Mods.RA/Minelayer.cs +++ b/OpenRA.Mods.RA/Minelayer.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA if (order.OrderString == "PlaceMinefield") { - var movement = self.Trait(); + var movement = self.Trait(); minefield = GetMinefieldCells(minefieldStart, order.TargetLocation, self.Info.Traits.Get().MinefieldDepth) @@ -130,7 +130,7 @@ namespace OpenRA.Mods.RA if (!minelayer.IsInWorld) return; - var movement = minelayer.Trait(); + var movement = minelayer.Trait(); var minefield = GetMinefieldCells(minefieldStart, lastMousePos, minelayer.Info.Traits.Get().MinefieldDepth) .Where(p => movement.CanEnterCell(p)).ToArray(); diff --git a/OpenRA.Mods.RA/Missions/Allies02Script.cs b/OpenRA.Mods.RA/Missions/Allies02Script.cs index 9703e9a999..f6a63cd091 100644 --- a/OpenRA.Mods.RA/Missions/Allies02Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies02Script.cs @@ -170,7 +170,7 @@ namespace OpenRA.Mods.RA.Missions if (yak == null || (yak != null && !yak.IsDead() && (yak.GetCurrentActivity() is FlyCircle || yak.IsIdle))) { var alliedUnitsNearYakPoint = world.FindAliveCombatantActorsInCircle(yakAttackPoint.CenterPosition, WRange.FromCells(10)) - .Where(a => a.Owner != soviets && a.HasTrait() && a != tanya && a != einstein && a != engineer); + .Where(a => a.Owner != soviets && a.HasTrait() && a != tanya && a != einstein && a != engineer); if (alliedUnitsNearYakPoint.Any()) YakStrafe(alliedUnitsNearYakPoint); } @@ -384,7 +384,7 @@ namespace OpenRA.Mods.RA.Missions bool AlliesNearTown() { return world.FindAliveCombatantActorsInCircle(townPoint.CenterPosition, WRange.FromCells(AlliedTownTransferRange)) - .Any(a => a.Owner == allies1 && a.HasTrait()); + .Any(a => a.Owner == allies1 && a.HasTrait()); } void TransferTownUnitsToAllies() @@ -399,7 +399,7 @@ namespace OpenRA.Mods.RA.Missions var sovietAttackUnits = world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint1.CenterPosition, WRange.FromCells(SovietTownAttackGroupRange)) .Union(world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint2.CenterPosition, WRange.FromCells(SovietTownAttackGroupRange))) .Union(world.FindAliveCombatantActorsInCircle(townPoint.CenterPosition, WRange.FromCells(AlliedTownTransferRange))) - .Where(a => a.HasTrait() && a.Owner == soviets); + .Where(a => a.HasTrait() && a.Owner == soviets); foreach (var unit in sovietAttackUnits) unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(townPoint.Location, SovietTownMoveNearEnough))); diff --git a/OpenRA.Mods.RA/Missions/Allies03Script.cs b/OpenRA.Mods.RA/Missions/Allies03Script.cs index f57bd3ac21..9bebeabf7c 100644 --- a/OpenRA.Mods.RA/Missions/Allies03Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies03Script.cs @@ -215,9 +215,10 @@ namespace OpenRA.Mods.RA.Missions foreach (var aircraft in SovietAircraft()) { + var pos = aircraft.CenterPosition; var plane = aircraft.Trait(); var ammo = aircraft.Trait(); - if ((plane.Altitude == 0 && ammo.FullAmmo()) || (plane.Altitude != 0 && ammo.HasAmmo())) + if ((pos.Z == 0 && ammo.FullAmmo()) || (pos.Z != 0 && ammo.HasAmmo())) { var enemy = FirstUnshroudedOrDefault(enemies.OrderBy(u => (aircraft.CenterPosition - u.CenterPosition).LengthSquared), world, 10); if (enemy != null) @@ -225,13 +226,13 @@ namespace OpenRA.Mods.RA.Missions if (!aircraft.IsIdle && aircraft.GetCurrentActivity().GetType() != typeof(FlyAttack)) aircraft.CancelActivity(); - if (plane.Altitude == 0) + if (pos.Z == 0) plane.UnReserve(); aircraft.QueueActivity(new FlyAttack(Target.FromActor(enemy))); } } - else if (plane.Altitude != 0 && !LandIsQueued(aircraft)) + else if (pos.Z != 0 && !LandIsQueued(aircraft)) { aircraft.CancelActivity(); aircraft.QueueActivity(new ReturnToBase(aircraft, null)); diff --git a/OpenRA.Mods.RA/Missions/Allies04Script.cs b/OpenRA.Mods.RA/Missions/Allies04Script.cs index dbe480c86b..e66a5335fd 100644 --- a/OpenRA.Mods.RA/Missions/Allies04Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies04Script.cs @@ -150,7 +150,7 @@ namespace OpenRA.Mods.RA.Missions var enemies = world.Actors.Where(u => u.Owner == creeps && u.HasTrait() && ((u.HasTrait() && !u.HasTrait() && !u.HasTrait()) || u.HasTrait()) && !u.IsDead() && u.IsInWorld); - var enemy = enemies.OrderBy(u => (attacker.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault(); + var enemy = enemies.ClosestTo(attacker); if (enemy != null) attacker.QueueActivity(new AttackMove.AttackMoveActivity(attacker, new Attack(Target.FromActor(enemy), WRange.FromCells(3)))); else diff --git a/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs b/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs index 277eae9720..c0e8661733 100644 --- a/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs +++ b/OpenRA.Mods.RA/Missions/DesertShellmapScript.cs @@ -217,14 +217,14 @@ namespace OpenRA.Mods.RA.Missions cargo.Load(chinook, world.CreateActor(false, ChinookCargo.Random(world.SharedRandom), allies, null, null)); var exit = lz.Info.Traits.WithInterface().FirstOrDefault(); - var offset = exit != null ? exit.SpawnOffsetVector : PVecInt.Zero; + var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero; - chinook.QueueActivity(new HeliFly(lz.CenterLocation + offset)); // no reservation of hpad but it's not needed + chinook.QueueActivity(new HeliFly(lz.CenterPosition + offset)); // no reservation of hpad but it's not needed chinook.QueueActivity(new Turn(0)); - chinook.QueueActivity(new HeliLand(false, 0)); + chinook.QueueActivity(new HeliLand(false)); chinook.QueueActivity(new UnloadCargo(true)); chinook.QueueActivity(new Wait(150)); - chinook.QueueActivity(new HeliFly(Util.CenterOfCell(entry))); + chinook.QueueActivity(new HeliFly(entry)); chinook.QueueActivity(new RemoveSelf()); } diff --git a/OpenRA.Mods.RA/Missions/FortLonestarScript.cs b/OpenRA.Mods.RA/Missions/FortLonestarScript.cs index 4134054f37..bc4360879a 100644 --- a/OpenRA.Mods.RA/Missions/FortLonestarScript.cs +++ b/OpenRA.Mods.RA/Missions/FortLonestarScript.cs @@ -79,11 +79,10 @@ namespace OpenRA.Mods.RA.Missions { var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == multi0) && ((u.HasTrait() && !u.HasTrait()))); - var targetEnemy = enemies.OrderBy(u => (self.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault(); + + var targetEnemy = enemies.ClosestTo(self); if (targetEnemy != null) - { self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(targetEnemy), WRange.FromCells(6)))); - } } void SendVehicles() diff --git a/OpenRA.Mods.RA/Missions/MissionUtils.cs b/OpenRA.Mods.RA/Missions/MissionUtils.cs index e397de1dad..e237223096 100644 --- a/OpenRA.Mods.RA/Missions/MissionUtils.cs +++ b/OpenRA.Mods.RA/Missions/MissionUtils.cs @@ -45,12 +45,12 @@ namespace OpenRA.Mods.RA.Missions public static Actor ExtractUnitWithChinook(World world, Player owner, Actor unit, CPos entry, CPos lz, CPos exit) { var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) }); - chinook.QueueActivity(new HeliFly(Util.CenterOfCell(lz))); + chinook.QueueActivity(new HeliFly(lz)); chinook.QueueActivity(new Turn(0)); - chinook.QueueActivity(new HeliLand(true, 0)); + chinook.QueueActivity(new HeliLand(true)); chinook.QueueActivity(new WaitFor(() => chinook.Trait().Passengers.Contains(unit))); chinook.QueueActivity(new Wait(150)); - chinook.QueueActivity(new HeliFly(Util.CenterOfCell(exit))); + chinook.QueueActivity(new HeliFly(exit)); chinook.QueueActivity(new RemoveSelf()); return chinook; } @@ -60,13 +60,13 @@ namespace OpenRA.Mods.RA.Missions var unit = world.CreateActor(false, unitName, new TypeDictionary { new OwnerInit(owner) }); var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) }); chinook.Trait().Load(chinook, unit); - chinook.QueueActivity(new HeliFly(Util.CenterOfCell(lz))); + chinook.QueueActivity(new HeliFly(lz)); chinook.QueueActivity(new Turn(0)); - chinook.QueueActivity(new HeliLand(true, 0)); + chinook.QueueActivity(new HeliLand(true)); chinook.QueueActivity(new UnloadCargo(true)); chinook.QueueActivity(new CallFunc(() => afterUnload(unit))); chinook.QueueActivity(new Wait(150)); - chinook.QueueActivity(new HeliFly(Util.CenterOfCell(exit))); + chinook.QueueActivity(new HeliFly(exit)); chinook.QueueActivity(new RemoveSelf()); return Pair.New(chinook, unit); } @@ -106,7 +106,7 @@ namespace OpenRA.Mods.RA.Missions public static bool AreaSecuredWithUnits(World world, Player player, WPos location, WRange range) { - var units = world.FindAliveCombatantActorsInCircle(location, range).Where(a => a.HasTrait()); + var units = world.FindAliveCombatantActorsInCircle(location, range).Where(a => a.HasTrait()); return units.Any() && units.All(a => a.Owner == player); } @@ -212,7 +212,7 @@ namespace OpenRA.Mods.RA.Missions var enemies = self.World.Actors.Where(u => u.AppearsHostileTo(self) && u.Owner == enemyPlayer && ((u.HasTrait() && !u.HasTrait()) || (u.HasTrait() && !u.HasTrait())) && u.IsInWorld && !u.IsDead()); - var enemy = enemies.OrderBy(u => (self.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault(); + var enemy = enemies.ClosestTo(self); if (enemy != null) self.QueueActivity(queued, new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(enemy), WRange.FromCells(3)))); } diff --git a/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs b/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs index 7971850508..b910b948e9 100644 --- a/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs +++ b/OpenRA.Mods.RA/Missions/Soviet01ClassicScript.cs @@ -126,8 +126,7 @@ namespace OpenRA.Mods.RA.Missions { var bridge = world.Actors .Where(a => a.HasTrait() && !a.IsDead()) - .OrderBy(a => (startJeep.CenterPosition - a.CenterPosition).LengthSquared) - .First(); + .ClosestTo(startJeep); Combat.DoExplosion(bridge, "Demolish", bridge.CenterPosition); world.WorldActor.Trait().AddEffect(15, bridge.CenterPosition, 6); bridge.Kill(bridge); diff --git a/OpenRA.Mods.RA/Missions/Survival01Script.cs b/OpenRA.Mods.RA/Missions/Survival01Script.cs index 7b37bf0fdc..4a77635de2 100644 --- a/OpenRA.Mods.RA/Missions/Survival01Script.cs +++ b/OpenRA.Mods.RA/Missions/Survival01Script.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -185,7 +185,7 @@ namespace OpenRA.Mods.RA.Missions var units = world.CreateActor((sovietInfantry).Random(world.SharedRandom), new TypeDictionary { new LocationInit(sovietinfantryentry1.Location), new OwnerInit(soviets) }); units.QueueActivity(new Move.Move(sovietinfantryrally1.Location, 3)); var unitsincircle = world.FindAliveCombatantActorsInCircle(sovietinfantryrally1.CenterPosition, WRange.FromCells(10)) - .Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait()); + .Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait()); if (unitsincircle.Count() >= sovietInfantryGroupSize) { foreach (var scatteredunits in unitsincircle) @@ -211,11 +211,10 @@ namespace OpenRA.Mods.RA.Missions { var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == allies) && ((u.HasTrait() && !u.HasTrait()) || u.HasTrait())); - var targetEnemy = enemies.OrderBy(u => (self.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault(); + + var targetEnemy = enemies.ClosestTo(self); if (targetEnemy != null) - { self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(targetEnemy), WRange.FromCells(3)))); - } } void ManageSovietUnits() diff --git a/OpenRA.Mods.RA/Missions/Survival02Script.cs b/OpenRA.Mods.RA/Missions/Survival02Script.cs index 7d2b69828d..47b54ab47b 100644 --- a/OpenRA.Mods.RA/Missions/Survival02Script.cs +++ b/OpenRA.Mods.RA/Missions/Survival02Script.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -299,7 +299,7 @@ namespace OpenRA.Mods.RA.Missions void ManageSovietUnits() { var units = world.FindAliveCombatantActorsInCircle(sovietrally.CenterPosition, WRange.FromCells(3)) - .Where(u => u.IsIdle && u.HasTrait() && u.HasTrait() && u.Owner == soviets); + .Where(u => u.IsIdle && u.HasTrait() && u.HasTrait() && u.Owner == soviets); if (units.Count() >= sovietAttackGroupSize) { foreach (var unit in units) diff --git a/OpenRA.Mods.RA/Move/Drag.cs b/OpenRA.Mods.RA/Move/Drag.cs index 307f71b5ee..41c8ff89ed 100755 --- a/OpenRA.Mods.RA/Move/Drag.cs +++ b/OpenRA.Mods.RA/Move/Drag.cs @@ -26,30 +26,36 @@ namespace OpenRA.Mods.RA.Move this.length = length; } - public override Activity Tick( Actor self ) + public override Activity Tick(Actor self) { - var mobile = self.Trait(); + var positionable = self.Trait(); + var mobile = positionable as Mobile; + var pos = length > 1 ? WPos.Lerp(start, end, ticks, length - 1) : end; - mobile.PxPosition = PPos.FromWPos(pos); + positionable.SetVisualPosition(self, pos); if (++ticks >= length) { - mobile.IsMoving = false; + if (mobile != null) + mobile.IsMoving = false; + return NextActivity; } - mobile.IsMoving = true; + if (mobile != null) + mobile.IsMoving = true; + return this; } - public override IEnumerable GetTargets( Actor self ) + public override IEnumerable GetTargets(Actor self) { yield return Target.FromPos(end); } // Cannot be cancelled - public override void Cancel( Actor self ) { } + public override void Cancel(Actor self) { } } } diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index f7679b096c..86ef2231a8 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -19,7 +19,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Move { [Desc("Unit is able to move.")] - public class MobileInfo : ITraitInfo, IFacingInfo, UsesInit, UsesInit, UsesInit + public class MobileInfo : ITraitInfo, IOccupySpaceInfo, IFacingInfo, UsesInit, UsesInit, UsesInit { [FieldLoader.LoadUsing("LoadSpeeds")] [Desc("Set Water: 0 for ground units and lower the value on rough terrain.")] @@ -35,7 +35,6 @@ namespace OpenRA.Mods.RA.Move public readonly bool OnRails = false; [Desc("Allow multiple (infantry) units in one cell.")] public readonly bool SharesCell = false; - public readonly int Altitude; public virtual object Create(ActorInitializer init) { return new Mobile(init, this); } @@ -81,14 +80,14 @@ namespace OpenRA.Mods.RA.Move return passability.ToBits(); } - public static readonly Dictionary SubCellOffsets = new Dictionary() + public static readonly Dictionary SubCellOffsets = new Dictionary() { - {SubCell.TopLeft, new PVecInt(-7,-6)}, - {SubCell.TopRight, new PVecInt(6,-6)}, - {SubCell.Center, new PVecInt(0,0)}, - {SubCell.BottomLeft, new PVecInt(-7,6)}, - {SubCell.BottomRight, new PVecInt(6,6)}, - {SubCell.FullCell, new PVecInt(0,0)}, + {SubCell.TopLeft, new WVec(-299, -256, 0)}, + {SubCell.TopRight, new WVec(256, -256, 0)}, + {SubCell.Center, new WVec(0, 0, 0)}, + {SubCell.BottomLeft, new WVec(-299, 256, 0)}, + {SubCell.BottomRight, new WVec(256, 256, 0)}, + {SubCell.FullCell, new WVec(0, 0, 0)}, }; static bool IsMovingInMyDirection(Actor self, Actor other) @@ -145,7 +144,7 @@ namespace OpenRA.Mods.RA.Move public int GetInitialFacing() { return InitialFacing; } } - public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IOccupySpace, IMove, IFacing, ISync + public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IFacing, ISync { public readonly Actor self; public readonly MobileInfo Info; @@ -163,11 +162,9 @@ namespace OpenRA.Mods.RA.Move set { __facing = value; } } - [Sync] public int Altitude { get; set; } - public int ROT { get { return Info.ROT; } } - [Sync] public PPos PxPosition { get; set; } + [Sync] public WPos CenterPosition { get; private set; } [Sync] public CPos fromCell { get { return __fromCell; } } [Sync] public CPos toCell { get { return __toCell; } } @@ -204,31 +201,36 @@ namespace OpenRA.Mods.RA.Move if (init.Contains()) { this.__fromCell = this.__toCell = init.Get(); - this.PxPosition = Util.CenterOfCell(fromCell) + MobileInfo.SubCellOffsets[fromSubCell]; + SetVisualPosition(self, fromCell.CenterPosition + MobileInfo.SubCellOffsets[fromSubCell]); } this.Facing = init.Contains() ? init.Get() : info.InitialFacing; - this.Altitude = init.Contains() ? init.Get() : 0; + + if (init.Contains()) + { + var z = init.Get() * 1024 / Game.CellSize; + SetVisualPosition(self, CenterPosition + new WVec(0, 0, z - CenterPosition.Z)); + } } public void SetPosition(Actor self, CPos cell) { SetLocation(cell,fromSubCell, cell,fromSubCell); - PxPosition = Util.CenterOfCell(fromCell) + MobileInfo.SubCellOffsets[fromSubCell]; + SetVisualPosition(self, fromCell.CenterPosition + MobileInfo.SubCellOffsets[fromSubCell]); FinishedMoving(self); } - public void SetPxPosition(Actor self, PPos px) + public void SetPosition(Actor self, WPos pos) { - var cell = px.ToCPos(); + var cell = pos.ToCPos(); SetLocation(cell,fromSubCell, cell,fromSubCell); - PxPosition = px; + SetVisualPosition(self, pos); FinishedMoving(self); } - public void AdjustPxPosition(Actor self, PPos px) /* visual hack only */ + public void SetVisualPosition(Actor self, WPos pos) { - PxPosition = px; + CenterPosition = pos; } public IEnumerable Orders { get { yield return new MoveOrderTargeter(Info); } } @@ -422,12 +424,7 @@ namespace OpenRA.Mods.RA.Move decimal speed = Info.Speed * Info.TerrainSpeeds[type].Speed; foreach (var t in self.TraitsImplementing()) speed *= t.GetSpeedModifier(); - return (int)(speed / 100); - } - - public int WorldMovementSpeedForCell(Actor self, CPos cell) - { - return MovementSpeedForCell(self, cell) * 1024 / Game.CellSize; + return (int)(speed / 100) * 1024 / (3 * Game.CellSize); } public void AddInfluence() diff --git a/OpenRA.Mods.RA/Move/Move.cs b/OpenRA.Mods.RA/Move/Move.cs index b0a527c1ec..e3d8e79e0e 100755 --- a/OpenRA.Mods.RA/Move/Move.cs +++ b/OpenRA.Mods.RA/Move/Move.cs @@ -20,11 +20,13 @@ namespace OpenRA.Mods.RA.Move { class Move : Activity { + static readonly List NoPath = new List(); + CPos? destination; WRange nearEnough; - public List path; + List path; Func> getPath; - public Actor ignoreBuilding; + Actor ignoreBuilding; // For dealing with blockers bool hasWaited; @@ -35,9 +37,9 @@ namespace OpenRA.Mods.RA.Move // Ignores lane bias and nearby units public Move(CPos destination) { - this.getPath = (self,mobile) => + this.getPath = (self, mobile) => self.World.WorldActor.Trait().FindPath( - PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, destination, false ) + PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false) .WithoutLaneBias()); this.destination = destination; this.nearEnough = WRange.Zero; @@ -45,29 +47,28 @@ namespace OpenRA.Mods.RA.Move // Hack for legacy code public Move(CPos destination, int nearEnough) - : this(destination, WRange.FromCells(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.getPath = (self, mobile) => self.World.WorldActor.Trait() + .FindUnitPath(mobile.toCell, destination, self); this.destination = destination; this.nearEnough = nearEnough; } public Move(CPos destination, Actor ignoreBuilding) { - this.getPath = (self,mobile) => + this.getPath = (self, mobile) => self.World.WorldActor.Trait().FindPath( PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false) - .WithIgnoredBuilding(ignoreBuilding) - ); + .WithIgnoredBuilding(ignoreBuilding)); this.destination = destination; this.nearEnough = WRange.Zero; this.ignoreBuilding = ignoreBuilding; } - static readonly List NoPath = new List(); public Move(Target target, WRange range) { this.getPath = (self, mobile) => @@ -85,7 +86,7 @@ namespace OpenRA.Mods.RA.Move public Move(Func> getPath) { - this.getPath = (_1,_2) => getPath(); + this.getPath = (_1, _2) => getPath(); this.destination = null; this.nearEnough = WRange.Zero; } @@ -110,15 +111,6 @@ namespace OpenRA.Mods.RA.Move public override Activity Tick(Actor self) { var mobile = self.Trait(); - var info = self.Info.Traits.Get(); - - if (mobile.Altitude != info.Altitude) - { - if (mobile.Altitude < info.Altitude) - ++mobile.Altitude; - - return this; - } if (destination == mobile.toCell) return NextActivity; @@ -132,7 +124,7 @@ namespace OpenRA.Mods.RA.Move } path = EvalPath(self, mobile); - SanityCheckPath( mobile ); + SanityCheckPath(mobile); } if (path.Count == 0) @@ -151,7 +143,7 @@ namespace OpenRA.Mods.RA.Move var firstFacing = Util.GetFacing(dir, mobile.Facing); if (firstFacing != mobile.Facing) { - path.Add( nextCell.Value.First ); + path.Add(nextCell.Value.First); return Util.SequenceActivities(new Turn(firstFacing), this); } else @@ -159,12 +151,11 @@ namespace OpenRA.Mods.RA.Move 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], + mobile.fromCell.CenterPosition + 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; } @@ -206,7 +197,7 @@ namespace OpenRA.Mods.RA.Move { // Are we close enough? var cellRange = nearEnough.Range / 1024; - if ((mobile.toCell - destination.Value).LengthSquared <= cellRange*cellRange) + if ((mobile.toCell - destination.Value).LengthSquared <= cellRange * cellRange) { path.Clear(); return null; @@ -255,9 +246,9 @@ namespace OpenRA.Mods.RA.Move return Pair.New(nextCell, subCell); } - public override void Cancel( Actor self ) + public override void Cancel(Actor self) { - path = new List(0); + path = NoPath; base.Cancel(self); } @@ -272,13 +263,13 @@ namespace OpenRA.Mods.RA.Move abstract class MovePart : Activity { - public readonly Move move; - public readonly PPos from, to; - public readonly int fromFacing, toFacing; - public int moveFraction; - public readonly int moveFractionTotal; + protected readonly Move move; + protected readonly WPos from, to; + protected readonly int fromFacing, toFacing; + protected readonly int moveFractionTotal; + protected int moveFraction; - public MovePart(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction) + public MovePart(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction) { this.move = move; this.from = from; @@ -286,7 +277,7 @@ namespace OpenRA.Mods.RA.Move this.fromFacing = fromFacing; this.toFacing = toFacing; this.moveFraction = startingFraction; - this.moveFractionTotal = 3*(to - from).Length; + this.moveFractionTotal = (to - from).Length; } public override void Cancel(Actor self) @@ -304,7 +295,7 @@ namespace OpenRA.Mods.RA.Move { var mobile = self.Trait(); var ret = InnerTick(self, mobile); - mobile.IsMoving = (ret is MovePart); + mobile.IsMoving = ret is MovePart; if (moveFraction > moveFractionTotal) moveFraction = moveFractionTotal; @@ -328,7 +319,7 @@ namespace OpenRA.Mods.RA.Move void UpdateCenterLocation(Actor self, Mobile mobile) { - mobile.PxPosition = PPos.Lerp(from, to, moveFraction, moveFractionTotal); + mobile.SetVisualPosition(self, WPos.Lerp(from, to, moveFraction, moveFractionTotal)); if (moveFraction >= moveFractionTotal) mobile.Facing = toFacing & 0xFF; @@ -346,7 +337,7 @@ namespace OpenRA.Mods.RA.Move class MoveFirstHalf : MovePart { - public MoveFirstHalf(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction) + public MoveFirstHalf(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction) : base(move, from, to, fromFacing, toFacing, startingFraction) { } static bool IsTurn(Mobile mobile, CPos nextCell) @@ -372,8 +363,7 @@ namespace OpenRA.Mods.RA.Move 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 - ); + moveFraction - moveFractionTotal); mobile.SetLocation(mobile.toCell, mobile.toSubCell, nextCell.Value.First, nextCell.Value.Second); return ret; @@ -385,11 +375,10 @@ namespace OpenRA.Mods.RA.Move var ret2 = new MoveSecondHalf( move, Util.BetweenCells(mobile.fromCell, mobile.toCell) + (fromSubcellOffset + toSubcellOffset) / 2, - Util.CenterOfCell(mobile.toCell) + toSubcellOffset, + mobile.toCell.CenterPosition + toSubcellOffset, mobile.Facing, mobile.Facing, - moveFraction - moveFractionTotal - ); + moveFraction - moveFractionTotal); mobile.EnteringCell(self); mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell); @@ -399,14 +388,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) {} + public MoveSecondHalf(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction) + : base(move, from, to, fromFacing, toFacing, startingFraction) { } 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.FinishedMoving(self); + mobile.SetPosition(self, mobile.toCell); return null; } } @@ -416,12 +403,10 @@ namespace OpenRA.Mods.RA.Move { public static bool IsMoving(this Actor self) { - if (self.IsIdle) + var a = self.GetCurrentActivity(); + if (a == null) return false; - Activity a = self.GetCurrentActivity(); - Debug.Assert(a != null); - // Dirty, but it suffices until we do something better: if (a.GetType() == typeof(Move)) return true; if (a.GetType() == typeof(MoveAdjacentTo)) return true; diff --git a/OpenRA.Mods.RA/Move/PathFinder.cs b/OpenRA.Mods.RA/Move/PathFinder.cs index 959e2cecf7..c09e6d8126 100755 --- a/OpenRA.Mods.RA/Move/PathFinder.cs +++ b/OpenRA.Mods.RA/Move/PathFinder.cs @@ -88,8 +88,7 @@ namespace OpenRA.Mods.RA.Move 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); + target -= MobileInfo.SubCellOffsets[srcSub]; // Select only the tiles that are within range from the requested SubCell // This assumes that the SubCell does not change during the path traversal diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 7073279bc8..b45286a48b 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -460,6 +460,7 @@ + diff --git a/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs b/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs index 20c8ee01cf..3b4d2f3ab5 100644 --- a/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs +++ b/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -50,7 +50,7 @@ namespace OpenRA.Mods.RA.Orders if (!world.LocalPlayer.Shroud.IsExplored(xy)) return "move-blocked"; - var movement = self.TraitOrDefault(); + var movement = self.TraitOrDefault(); return (movement.CanEnterCell(xy)) ? "chrono-target" : "move-blocked"; } } diff --git a/OpenRA.Mods.RA/ParaDrop.cs b/OpenRA.Mods.RA/ParaDrop.cs index 9adc524ad7..992d8c3033 100644 --- a/OpenRA.Mods.RA/ParaDrop.cs +++ b/OpenRA.Mods.RA/ParaDrop.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made @@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA bool IsSuitableCell(Actor actorToDrop, CPos p) { - return actorToDrop.Trait().CanEnterCell(p); + return actorToDrop.Trait().CanEnterCell(p); } void FinishedDropping(Actor self) diff --git a/OpenRA.Mods.RA/Player/PlayerStatistics.cs b/OpenRA.Mods.RA/Player/PlayerStatistics.cs index 5091501494..631c10c221 100644 --- a/OpenRA.Mods.RA/Player/PlayerStatistics.cs +++ b/OpenRA.Mods.RA/Player/PlayerStatistics.cs @@ -112,7 +112,7 @@ namespace OpenRA.Mods.RA attackerStats.BuildingsKilled++; defenderStats.BuildingsDead++; } - else if (self.HasTrait()) + else if (self.HasTrait()) { attackerStats.UnitsKilled++; defenderStats.UnitsDead++; diff --git a/OpenRA.Mods.RA/Production.cs b/OpenRA.Mods.RA/Production.cs index d8718b08f9..ad6c8241e3 100755 --- a/OpenRA.Mods.RA/Production.cs +++ b/OpenRA.Mods.RA/Production.cs @@ -31,13 +31,15 @@ namespace OpenRA.Mods.RA public class ExitInfo : TraitInfo { public readonly int2 SpawnOffset = int2.Zero; // in px relative to CenterLocation - public readonly int2 ExitCell = int2.Zero; // in cells relative to TopLeft + public readonly int2 ExitCell = int2.Zero; // in cells relative to TopLeft public readonly int Facing = -1; - public PVecInt SpawnOffsetVector { get { return (PVecInt)SpawnOffset; } } + // TODO: Push this conversion into the yaml + public WVec SpawnOffsetVector { get { return new WVec(SpawnOffset.X, SpawnOffset.Y, 0) * 1024 / Game.CellSize; } } public CVec ExitCellVector { get { return (CVec)ExitCell; } } } - public class Exit {} + + public class Exit { } public class Production { @@ -50,7 +52,7 @@ namespace OpenRA.Mods.RA public void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo) { var exit = self.Location + exitinfo.ExitCellVector; - var spawn = (self.Trait().PxPosition + exitinfo.SpawnOffsetVector).ToWPos(0); + var spawn = self.CenterPosition + exitinfo.SpawnOffsetVector; var to = exit.CenterPosition; var fi = producee.Traits.Get(); @@ -65,8 +67,8 @@ namespace OpenRA.Mods.RA // TODO: Move this into an *Init // TODO: We should be adjusting the actual position for aircraft, not just visuals. - var teleportable = newUnit.Trait(); - teleportable.AdjustPxPosition(newUnit, PPos.FromWPos(spawn)); + var teleportable = newUnit.Trait(); + teleportable.SetVisualPosition(newUnit, spawn); // TODO: Generalize this for non-mobile (e.g. aircraft) too // Remember to update the Enter activity too @@ -74,8 +76,8 @@ namespace OpenRA.Mods.RA if (mobile != null) { // Animate the spawn -> exit transition - var speed = mobile.WorldMovementSpeedForCell(newUnit, exit); - var length = speed > 0 ? (int)((to - spawn).Length * 3 / speed) : 0; + var speed = mobile.MovementSpeedForCell(newUnit, exit); + var length = speed > 0 ? (to - spawn).Length / speed : 0; newUnit.QueueActivity(new Drag(spawn, to, length)); } @@ -104,7 +106,7 @@ namespace OpenRA.Mods.RA var helicopter = newUnit.TraitOrDefault(); if (helicopter != null) { - newUnit.QueueActivity(new HeliFly(Util.CenterOfCell(rp.rallyPoint))); + newUnit.QueueActivity(new HeliFly(rp.rallyPoint)); return rp.rallyPoint; } diff --git a/OpenRA.Mods.RA/Render/WithRotor.cs b/OpenRA.Mods.RA/Render/WithRotor.cs index 2da92ea359..9a7202a23a 100755 --- a/OpenRA.Mods.RA/Render/WithRotor.cs +++ b/OpenRA.Mods.RA/Render/WithRotor.cs @@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Render public void Tick(Actor self) { - var isFlying = self.Trait().Altitude > 0 && !self.IsDead(); + var isFlying = self.CenterPosition.Z > 0 && !self.IsDead(); if (isFlying ^ (rotorAnim.CurrentSequence.Name != "rotor")) return; diff --git a/OpenRA.Mods.RA/Render/WithShadow.cs b/OpenRA.Mods.RA/Render/WithShadow.cs index a6e265921f..6cde2c7c3c 100644 --- a/OpenRA.Mods.RA/Render/WithShadow.cs +++ b/OpenRA.Mods.RA/Render/WithShadow.cs @@ -14,7 +14,6 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; using OpenRA.Mods.RA.Air; -using OpenRA.Mods.RA.Move; namespace OpenRA.Mods.RA.Render { @@ -24,16 +23,17 @@ namespace OpenRA.Mods.RA.Render { public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { - var move = self.Trait(); + var ios = self.Trait(); /* rude hack */ - var visualOffset = ((move is Helicopter || move is Mobile) && move.Altitude > 0) + var flying = ios.CenterPosition.Z > 0; + var visualOffset = (ios is Helicopter && flying) ? (int)Math.Abs((self.ActorID + Game.LocalTick) / 5 % 4 - 1) - 1 : 0; var shadowSprites = r.Select(a => a.WithPalette(wr.Palette("shadow")) .WithPos(a.Pos - new WVec(0, 0, a.Pos.Z)).WithZOffset(a.ZOffset + a.Pos.Z)); - var flyingSprites = (move.Altitude <= 0) ? r : + var flyingSprites = !flying ? r : r.Select(a => a.WithPos(a.Pos - new WVec(0,0,43*visualOffset))); return shadowSprites.Concat(flyingSprites); diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index f9b9dd77d5..91240d58a8 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -449,6 +449,7 @@ Armor: Type: Light Husk: + AllowedTerrain: Clear, Rough, Road, Tiberium, BlueTiberium, Beach HiddenUnderFog: AppearsOnRadar: Burns: diff --git a/mods/d2k/rules/aircraft.yaml b/mods/d2k/rules/aircraft.yaml index c7194ccde4..ff46bdb260 100644 --- a/mods/d2k/rules/aircraft.yaml +++ b/mods/d2k/rules/aircraft.yaml @@ -19,7 +19,7 @@ LandableTerrainTypes: Sand, Rock, Transition, Spice, Dune RepairBuildings: repair RearmBuildings: starporta,starporto,starporth - MinimalLandAltitude: 25 + LandAltitude: 800 RenderUnit: WithCargo: LocalOffset: 0,0,-854 @@ -28,7 +28,7 @@ Types: Vehicle MaxWeight: 1 PipCount: 1 - minimalUnloadAltitude: 25 + MaximumUnloadAltitude: 800 LeavesHusk: HuskActor: CARRYALL.Husk diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index f465db8147..af1f33ef81 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -78,6 +78,7 @@ Armor: Type: Light Husk: + AllowedTerrain: Sand, Rock, Transition, Concrete, Spice, SpiceBlobs, Dune HiddenUnderFog: AppearsOnRadar: Burns: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index b9abf0f52b..e5259b6b02 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -373,6 +373,7 @@ ^Husk: Husk: + AllowedTerrain: Clear, Rough, Road, Ore, Gems, Beach RenderUnit: Health: HP: 140 @@ -385,6 +386,7 @@ Types:Husk BelowUnits: BodyOrientation: + Chronoshiftable: ^HelicopterHusk: Inherits: ^Husk