diff --git a/OpenRa.Game/Effects/Parachute.cs b/OpenRa.Game/Effects/Parachute.cs index 20bdfc0814..a8ff4570ec 100644 --- a/OpenRa.Game/Effects/Parachute.cs +++ b/OpenRa.Game/Effects/Parachute.cs @@ -27,7 +27,10 @@ namespace OpenRa.Effects this.owner = owner; anim = new Animation(image); - anim.PlayFetchIndex("idle", () => 0); + if (anim.HasSequence("idle")) + anim.PlayFetchIndex("idle", () => 0); + else + anim.PlayFetchIndex("stand", () => 0); anim.Tick(); paraAnim = new Animation("parach"); @@ -44,10 +47,9 @@ namespace OpenRa.Effects world.AddFrameEndTask(w => { w.Remove(this); - cargo.CancelActivity(); - cargo.CenterLocation = location; - cargo.Location = ((1 / 24f) * location).ToInt2(); w.Add(cargo); + cargo.CancelActivity(); + cargo.traits.Get().TeleportTo(cargo, ((1 / 24f) * location).ToInt2()); }); } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index e57cf60c69..601741d69e 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -225,6 +225,7 @@ + diff --git a/OpenRa.Game/Traits/Activities/FlyAttack.cs b/OpenRa.Game/Traits/Activities/FlyAttack.cs index 64f043763e..78333f2554 100644 --- a/OpenRa.Game/Traits/Activities/FlyAttack.cs +++ b/OpenRa.Game/Traits/Activities/FlyAttack.cs @@ -29,4 +29,26 @@ namespace OpenRa.Traits.Activities public void Cancel(Actor self) { Target = null; NextActivity = null; } } + + class FlyCircle : IActivity + { + public IActivity NextActivity { get; set; } + int2 Target; + bool isCanceled; + + public FlyCircle(int2 target) { Target = target; } + + public IActivity Tick(Actor self) + { + if (isCanceled) + return NextActivity; + + return Util.SequenceActivities( + new Fly(Util.CenterOfCell(Target)), + new FlyTimed(50, 20), + this); + } + + public void Cancel(Actor self) { isCanceled = true; NextActivity = null; } + } } diff --git a/OpenRa.Game/Traits/ParaDrop.cs b/OpenRa.Game/Traits/ParaDrop.cs new file mode 100644 index 0000000000..88afc17bb0 --- /dev/null +++ b/OpenRa.Game/Traits/ParaDrop.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Traits.Activities; +using OpenRa.Effects; + +namespace OpenRa.Traits +{ + class ParaDropInfo : ITraitInfo + { + public readonly int LZRange = 4; + public object Create(Actor self) { return new ParaDrop(); } + } + + class ParaDrop : ITick + { + readonly List droppedAt = new List(); + int2 lz; + + public void SetLZ( int2 lz ) + { + this.lz = lz; + droppedAt.Clear(); + } + + public void Tick(Actor self) + { + var r = self.Info.Traits.Get().LZRange; + + if ((self.Location - lz).LengthSquared <= r * r && !droppedAt.Contains(self.Location)) + { + // todo: check is this is a good drop cell. + + // unload a dude here + droppedAt.Add(self.Location); + + var cargo = self.traits.Get(); + if (cargo.IsEmpty(self)) + FinishedDropping(self); + else + { + var a = cargo.Unload(self); + var rs = a.traits.Get(); + + self.World.AddFrameEndTask(w => w.Add( + new Parachute(self.Owner, rs.anim.Name, + self.CenterLocation, + self.traits.Get().Altitude, a))); + + Sound.Play("chute1.aud"); + } + } + } + + void FinishedDropping(Actor self) + { + // this kindof sucks, actually. + self.CancelActivity(); + self.QueueActivity(new Fly(Util.CenterOfCell(self.World.ChooseRandomEdgeCell()))); + self.QueueActivity(new RemoveSelf()); + } + } +} diff --git a/OpenRa.Game/Traits/ParatroopersPower.cs b/OpenRa.Game/Traits/ParatroopersPower.cs index 576a280b15..1221fa59f0 100644 --- a/OpenRa.Game/Traits/ParatroopersPower.cs +++ b/OpenRa.Game/Traits/ParatroopersPower.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using OpenRa.Traits.Activities; namespace OpenRa.Traits { class ParatroopersPowerInfo : SupportPowerInfo { - /* todo... */ + public string[] DropItems = { }; public override object Create(Actor self) { return new ParatroopersPower(self,this); } } @@ -45,7 +46,19 @@ namespace OpenRa.Traits if (self.Owner == self.World.LocalPlayer) Game.controller.CancelInputMode(); - /* todo:... */ + var startPos = self.World.ChooseRandomEdgeCell(); + self.World.AddFrameEndTask(w => + { + var a = w.CreateActor("BADR", startPos, Owner); + + a.CancelActivity(); + a.QueueActivity(new FlyCircle(order.TargetLocation)); + a.traits.Get().SetLZ(order.TargetLocation); + + var cargo = a.traits.Get(); + foreach (var p in self.Info.Traits.Get().DropItems) + cargo.Load(a, new Actor(self.World, p.ToLowerInvariant(), a.Location, a.Owner)); + }); FinishActivate(); } diff --git a/OpenRa.Game/Traits/SpyPlanePower.cs b/OpenRa.Game/Traits/SpyPlanePower.cs index 9316f784f2..03da94c2ef 100644 --- a/OpenRa.Game/Traits/SpyPlanePower.cs +++ b/OpenRa.Game/Traits/SpyPlanePower.cs @@ -23,18 +23,6 @@ namespace OpenRa.Traits Sound.Play("slcttgt1.aud"); } - static int2 ChooseRandomEdgeCell(World w) - { - var isX = Game.SharedRandom.Next(2) == 0; - var edge = Game.SharedRandom.Next(2) == 0; - - return new int2( - isX ? Game.SharedRandom.Next(w.Map.XOffset, w.Map.XOffset + w.Map.Width) - : (edge ? w.Map.XOffset : w.Map.XOffset + w.Map.Width), - !isX ? Game.SharedRandom.Next(w.Map.YOffset, w.Map.YOffset + w.Map.Height) - : (edge ? w.Map.YOffset : w.Map.YOffset + w.Map.Height)); - } - public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "SpyPlane") @@ -44,8 +32,8 @@ namespace OpenRa.Traits if (order.Player == Owner.World.LocalPlayer) Game.controller.CancelInputMode(); - var enterCell = ChooseRandomEdgeCell(self.World); - var exitCell = ChooseRandomEdgeCell(self.World); + var enterCell = self.World.ChooseRandomEdgeCell(); + var exitCell = self.World.ChooseRandomEdgeCell(); var plane = self.World.CreateActor("U2", enterCell, self.Owner); plane.CancelActivity(); diff --git a/OpenRa.Game/WorldUtils.cs b/OpenRa.Game/WorldUtils.cs index 77fade7f71..8b198a323d 100755 --- a/OpenRa.Game/WorldUtils.cs +++ b/OpenRa.Game/WorldUtils.cs @@ -168,5 +168,17 @@ namespace OpenRa world.players.Values.FirstOrDefault(p => p.InternalName == parts[0]) ?? world.players[0]); } } + + public static int2 ChooseRandomEdgeCell(this World w) + { + var isX = Game.SharedRandom.Next(2) == 0; + var edge = Game.SharedRandom.Next(2) == 0; + + return new int2( + isX ? Game.SharedRandom.Next(w.Map.XOffset, w.Map.XOffset + w.Map.Width) + : (edge ? w.Map.XOffset : w.Map.XOffset + w.Map.Width), + !isX ? Game.SharedRandom.Next(w.Map.YOffset, w.Map.YOffset + w.Map.Height) + : (edge ? w.Map.YOffset : w.Map.YOffset + w.Map.Height)); + } } } diff --git a/mods/ra/merge-rules.yaml b/mods/ra/merge-rules.yaml index 0cd6cac7c8..abfc1dff4a 100644 --- a/mods/ra/merge-rules.yaml +++ b/mods/ra/merge-rules.yaml @@ -34,6 +34,14 @@ Player: LongDesc: Reveals an area of the map. Prerequisites: AFLD TechLevel: 5 + ParatroopersPower: + Image: pinficon + ChargeTime: 6 + Description: Paratroopers + LongDesc: A Badger drops a squad of Riflemen \n anywhere on the map + Prerequisites: AFLD + TechLevel: 5 + DropItems: E1,E1,E1,E3,E3 NukePower: Image: atomicon ChargeTime: 13 @@ -140,3 +148,8 @@ CRATE: HP: 1 RenderUnit: BelowUnits: + +BADR: + ParaDrop: + LZRange: 4 + -Selectable: \ No newline at end of file diff --git a/mods/ra/rules.yaml b/mods/ra/rules.yaml index dac09e2711..5fa4f44e7d 100644 --- a/mods/ra/rules.yaml +++ b/mods/ra/rules.yaml @@ -34,6 +34,14 @@ Player: LongDesc: Reveals an area of the map. Prerequisites: AFLD TechLevel: 5 + ParatroopersPower: + Image: pinficon + ChargeTime: 6 + Description: Paratroopers + LongDesc: A Badger drops a squad of Riflemen \n anywhere on the map + Prerequisites: AFLD + TechLevel: 5 + DropItems: E1,E1,E1,E3,E3 NukePower: Image: atomicon ChargeTime: 13 @@ -430,6 +438,24 @@ CRATE: RenderUnit: BelowUnits: +BADR: + ParaDrop: + LZRange: 4 + Inherits: ^Plane + Unit: + HP: 60 + Armor: light + ROT: 5 + Sight: 0 + Speed: 16 + Plane: + RenderUnit: + WithShadow: + IronCurtainable: + Cargo: + Passengers: 10 + -Selectable: + V2RL: Inherits: ^Vehicle Buildable: @@ -1027,21 +1053,6 @@ U2: WithShadow: IronCurtainable: -BADR: - Inherits: ^Plane - Unit: - HP: 60 - Armor: light - ROT: 5 - Sight: 0 - Speed: 16 - Plane: - RenderUnit: - WithShadow: - IronCurtainable: - Cargo: - Passengers: 5 - PBOX: Inherits: ^Building Buildable: diff --git a/mods/ra/sequences.xml b/mods/ra/sequences.xml index c6f0ce7331..91c0d64530 100644 --- a/mods/ra/sequences.xml +++ b/mods/ra/sequences.xml @@ -1051,4 +1051,7 @@ + + + \ No newline at end of file diff --git a/mods/ra/units.ini b/mods/ra/units.ini index 196f7c2c07..3fcfb7032f 100644 --- a/mods/ra/units.ini +++ b/mods/ra/units.ini @@ -209,6 +209,7 @@ LongDesc=Helicopter Gunship with Chainguns.\n Strong vs Infantry, Light Vehicle Traits=Unit, Plane, RenderUnit, WithShadow, IronCurtainable [BADR] Traits=Unit, Plane, RenderUnit, WithShadow, IronCurtainable, Cargo +Passengers=10