diff --git a/OpenRA.Mods.RA/ChronoshiftDeploy.cs b/OpenRA.Mods.RA/ChronoshiftDeploy.cs index a6837e000b..9be7a0473d 100644 --- a/OpenRA.Mods.RA/ChronoshiftDeploy.cs +++ b/OpenRA.Mods.RA/ChronoshiftDeploy.cs @@ -8,23 +8,34 @@ */ #endregion +using System.Drawing; using System.Collections.Generic; using OpenRA.Effects; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Orders; using OpenRA.Traits; +using OpenRA.Graphics; namespace OpenRA.Mods.RA { - class ChronoshiftDeployInfo : TraitInfo + class ChronoshiftDeployInfo : ITraitInfo { - public readonly int ChargeTime = 120; // Seconds + public readonly int ChargeTime = 60; // seconds + public readonly int JumpDistance = 10; + public object Create(ActorInitializer init) { return new ChronoshiftDeploy(init.self, this); } } class ChronoshiftDeploy : IIssueOrder, IResolveOrder, ITick, IPips, IOrderVoice, ISync { - // Recharge logic - [Sync] int chargeTick = 0; // How long until we can chronoshift again? + [Sync] int chargeTick = 0; + public readonly ChronoshiftDeployInfo Info; + readonly Actor self; + + public ChronoshiftDeploy(Actor self, ChronoshiftDeployInfo info) + { + this.self = self; + this.Info = info; + } public void Tick(Actor self) { @@ -34,29 +45,28 @@ namespace OpenRA.Mods.RA public IEnumerable Orders { - get { yield return new DeployOrderTargeter( "ChronoshiftDeploy", 5, () => chargeTick <= 0 ); } + get { yield return new DeployOrderTargeter("ChronoshiftJump", 5, () => chargeTick <= 0); } } - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) { - if( order.OrderID == "ChronoshiftDeploy" ) - if (chargeTick <= 0) - self.World.OrderGenerator = new SetChronoTankDestination( self ); + if (order.OrderID == "ChronoshiftJump" && chargeTick <= 0) + self.World.OrderGenerator = new ChronoTankOrderGenerator(self); - return null; + return new Order("ChronoshiftJump", self, false); // Hack until we can return null } public void ResolveOrder(Actor self, Order order) { var movement = self.TraitOrDefault(); - if (order.OrderString == "ChronoshiftSelf" && movement.CanEnterCell(order.TargetLocation)) + if (order.OrderString == "ChronoshiftJump") { - if (self.Owner == self.World.LocalPlayer) - self.World.CancelInputMode(); - - self.CancelActivity(); - self.QueueActivity(new Teleport(null, order.TargetLocation, true)); - chargeTick = 25 * self.Info.Traits.Get().ChargeTime; + if (CanJumpTo(order.TargetLocation)) + { + self.CancelActivity(); + self.QueueActivity(new Teleport(null, order.TargetLocation, true)); + chargeTick = 25 * Info.ChargeTime; + } } } @@ -71,7 +81,7 @@ namespace OpenRA.Mods.RA const int numPips = 5; for (int i = 0; i < numPips; i++) { - if ((1 - chargeTick * 1.0f / (25 * self.Info.Traits.Get().ChargeTime)) * numPips < i + 1) + if ((1 - chargeTick * 1.0f / (25 * Info.ChargeTime)) * numPips < i + 1) { yield return PipType.Transparent; continue; @@ -93,5 +103,61 @@ namespace OpenRA.Mods.RA } } } + + public bool CanJumpTo(CPos xy) + { + var movement = self.TraitOrDefault(); + + if (chargeTick <= 0 // Can jump + && self.World.LocalPlayer.Shroud.IsExplored(xy) // Not in shroud + && movement.CanEnterCell(xy) // Can enter cell + && (self.Location - xy).Length <= Info.JumpDistance) // Within jump range + return true; + else + return false; + } + } + + class ChronoTankOrderGenerator : IOrderGenerator + { + readonly Actor self; + + public ChronoTankOrderGenerator(Actor self) { this.self = self; } + + public IEnumerable Order(World world, CPos xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + world.CancelInputMode(); + yield break; + } + + var queued = mi.Modifiers.HasModifier(Modifiers.Shift); + + var cinfo = self.Trait(); + if (cinfo.CanJumpTo(xy)) + { + self.World.CancelInputMode(); + yield return new Order("ChronoshiftJump", self, queued) { TargetLocation = xy }; + } + } + + public string GetCursor(World world, CPos xy, MouseInput mi) + { + var cinfo = self.Trait(); + if (cinfo.CanJumpTo(xy)) + return "chrono-target"; + else + return "move-blocked"; + } + + public void Tick(World world) { } + public void RenderAfterWorld(WorldRenderer wr, World world) { } + public void RenderBeforeWorld(WorldRenderer wr, World world) + { + wr.DrawRangeCircle( + Color.FromArgb(128, Color.Magenta), + self.CenterLocation.ToFloat2(), (int)self.Trait().Info.JumpDistance); + } } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 9394897ea0..bddb801f01 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -254,7 +254,6 @@ - @@ -435,4 +434,4 @@ copy "$(TargetPath)" "$(SolutionDir)mods/ra/" cd "$(SolutionDir)" - + \ No newline at end of file diff --git a/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs b/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs deleted file mode 100644 index 20c8ee01cf..0000000000 --- a/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs +++ /dev/null @@ -1,57 +0,0 @@ -#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 - * 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.Collections.Generic; -using System.Drawing; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Orders -{ - class SetChronoTankDestination : IOrderGenerator - { - public readonly Actor self; - - public SetChronoTankDestination(Actor self) - { - this.self = self; - } - - public IEnumerable Order(World world, CPos xy, MouseInput mi) - { - if (mi.Button == MouseButton.Left) - { - world.CancelInputMode(); - yield break; - } - - var queued = mi.Modifiers.HasModifier(Modifiers.Shift); - if (world.LocalPlayer.Shroud.IsExplored(xy)) - yield return new Order("ChronoshiftSelf", self, queued) { TargetLocation = xy }; - } - - public void Tick( World world ) { } - public void RenderAfterWorld( WorldRenderer wr, World world ) - { - wr.DrawSelectionBox(self, Color.White); - } - - public void RenderBeforeWorld( WorldRenderer wr, World world ) { } - - public string GetCursor(World world, CPos xy, MouseInput mi) - { - if (!world.LocalPlayer.Shroud.IsExplored(xy)) - return "move-blocked"; - - var movement = self.TraitOrDefault(); - return (movement.CanEnterCell(xy)) ? "chrono-target" : "move-blocked"; - } - } -} diff --git a/mods/ra/bits/ctnk.shp b/mods/ra/bits/ctnk.shp new file mode 100644 index 0000000000..51237f3dd0 Binary files /dev/null and b/mods/ra/bits/ctnk.shp differ diff --git a/mods/ra/bits/ctnkicon.shp b/mods/ra/bits/ctnkicon.shp new file mode 100644 index 0000000000..6b339487a7 Binary files /dev/null and b/mods/ra/bits/ctnkicon.shp differ diff --git a/mods/ra/rules/vehicles.yaml b/mods/ra/rules/vehicles.yaml index 50e9d72688..70351f6dc7 100644 --- a/mods/ra/rules/vehicles.yaml +++ b/mods/ra/rules/vehicles.yaml @@ -603,3 +603,34 @@ DTRK: -IronCurtainable: Chronoshiftable: ExplodeInstead: yes + +CTNK: + Inherits: ^Vehicle + Buildable: + Queue: Vehicle + BuildPaletteOrder: 140 + Prerequisites: atek + Owner: allies + Valued: + Cost: 1200 + Tooltip: + Name: Chrono Tank + Description: Chrono Tank, teleports to areas within range.\n Strong vs Vehicles, Buildings\n Weak vs Tanks + Selectable: + Bounds: 28,28 + Health: + HP: 200 + Armor: + Type: Light + Mobile: + Speed: 8 + RevealsShroud: + Range: 3 + RenderUnit: + AutoTarget: + AttackFrontal: + PrimaryWeapon: ChronoTusk + SecondaryWeapon: ChronoTusk + PrimaryLocalOffset: -4,0,0,0,0, -4,0,0,0,0 + SecondaryLocalOffset: 4,0,0,0,25, 4,0,0,0,-25 + ChronoshiftDeploy: diff --git a/mods/ra/sequences.yaml b/mods/ra/sequences.yaml index cb039c2b92..f23331066e 100644 --- a/mods/ra/sequences.yaml +++ b/mods/ra/sequences.yaml @@ -2270,6 +2270,11 @@ e8: Length: * dtrk: + idle: + Start: 0 + Facings: 32 + +ctnk: idle: Start: 0 Facings: 32 \ No newline at end of file diff --git a/mods/ra/weapons.yaml b/mods/ra/weapons.yaml index 754ed5ceab..ddf6389dbd 100644 --- a/mods/ra/weapons.yaml +++ b/mods/ra/weapons.yaml @@ -1245,3 +1245,34 @@ Sniper: Light: 5% Heavy: 5% InfDeath: 2 + +ChronoTusk: + ROF: 60 + Range: 6 + Report: MISSILE6 + ValidTargets: Ground + Projectile: Missile + Speed: 35 + Arm: 2 + High: true + Shadow: false + Proximity: true + Trail: smokey + ContrailLength: 10 + Inaccuracy: 3 + Image: DRAGON + ROT: 10 + RangeLimit: 35 + Warhead: + Spread: 3 + Versus: + None: 50% + Wood: 75% + Light: 75% + Heavy: 50% + Concrete: 25% + Explosion: med_explosion + WaterExplosion: med_splash + InfDeath: 4 + SmudgeType: Crater + Damage: 20