diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 03730391eb..cfc727e142 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -181,6 +181,7 @@ + @@ -201,6 +202,7 @@ + diff --git a/OpenRa.Game/Traits/Activities/UndeployMcv.cs b/OpenRa.Game/Traits/Activities/UndeployMcv.cs new file mode 100644 index 0000000000..7e9241157d --- /dev/null +++ b/OpenRa.Game/Traits/Activities/UndeployMcv.cs @@ -0,0 +1,43 @@ +using System; + +namespace OpenRa.Game.Traits.Activities +{ + class UndeployMcv : IActivity + { + public IActivity NextActivity { get; set; } + bool started; + + void DoUndeploy(World w,Actor self) + { + self.Health = 0; + foreach (var ns in self.traits.WithInterface()) + ns.Sold(self); + w.Remove(self); + + var mcv = new Actor(Rules.UnitInfo["MCV"], self.Location + new int2(1, 1), self.Owner); + mcv.traits.Get().Facing = 96; + w.Add(mcv); + } + + public IActivity Tick(Actor self) + { + if (!started) + { + var rb = self.traits.Get(); + rb.PlayCustomAnimBackwards(self, "make", + () => Game.world.AddFrameEndTask(w => DoUndeploy(w,self))); + + Sound.Play("cashturn.aud"); + started = true; + } + + return this; + } + + public void Cancel(Actor self) + { + // Cancel can't happen between this being moved to the head of the list, and it being Ticked. + throw new InvalidOperationException("UndeployMcvAction: Cancel() should never occur."); + } + } +} diff --git a/OpenRa.Game/Traits/McvUndeploy.cs b/OpenRa.Game/Traits/McvUndeploy.cs new file mode 100644 index 0000000000..6b2b37a3da --- /dev/null +++ b/OpenRa.Game/Traits/McvUndeploy.cs @@ -0,0 +1,69 @@ +using OpenRa.Game.GameRules; +using OpenRa.Game.Traits.Activities; + +namespace OpenRa.Game.Traits +{ + class McvUndeploy : IOrder, IMovement + { + readonly Actor self; + + public McvUndeploy(Actor self) + { + this.self = self; + } + + public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) + { + if (!Rules.General.MCVUndeploy) return null; + + if (mi.Button == MouseButton.Left) return null; + + if (underCursor != null) + { + // force-move + if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null; + if (!Game.IsActorCrushableByActor(underCursor, self)) return null; + } + + return new Order("Move", self, null, xy, null); + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Move") + { + self.CancelActivity(); + self.QueueActivity(new UndeployMcv()); + } + } + + // HACK: This should make reference to an MCV actor, and use of its Mobile trait + public UnitMovementType GetMovementType() + { + return UnitMovementType.Wheel; + } + + public bool CanEnterCell(int2 a) + { + if (!Game.BuildingInfluence.CanMoveHere(a)) return false; + + var crushable = true; + foreach (Actor actor in Game.UnitInfluence.GetUnitsAt(a)) + { + if (actor == self) continue; + + if (!Game.IsActorCrushableByActor(actor, self)) + { + crushable = false; + break; + } + } + + if (!crushable) return false; + + return Rules.Map.IsInMap(a.X, a.Y) && + TerrainCosts.Cost(GetMovementType(), + Rules.TileSet.GetWalkability(Rules.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; + } + } +} diff --git a/units.ini b/units.ini index 2f63abcc4a..9150efbf3f 100644 --- a/units.ini +++ b/units.ini @@ -373,7 +373,7 @@ SelectionPriority=3 LongDesc=Produces and repairs submarines and \ntransports [FACT] Description=Construction Yard -Traits=Building, RenderBuilding +Traits=Building, RenderBuilding, McvUndeploy Dimensions=3,3 Footprint=xxx xxx xxx Produces=Building,Defense