diff --git a/OpenRA.Mods.Common/Traits/FireWarheads.cs b/OpenRA.Mods.Common/Traits/FireWarheads.cs new file mode 100644 index 0000000000..2ab3107f2a --- /dev/null +++ b/OpenRA.Mods.Common/Traits/FireWarheads.cs @@ -0,0 +1,89 @@ +#region Copyright & License Information +/* + * Copyright (c) The OpenRA Developers and Contributors + * 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Detonate defined warheads at the current location at a set interval.")] + public class FireWarheadsInfo : PausableConditionalTraitInfo, Requires, IRulesetLoaded + { + [WeaponReference] + [FieldLoader.Require] + [Desc("Weapons to fire.")] + public readonly string[] Weapons = Array.Empty(); + + [Desc("How long (in ticks) to wait before the first detonation.")] + public readonly int StartCooldown = 0; + + [Desc("How long (in ticks) to wait after a detonation.")] + public readonly int Interval = 1; + + public override object Create(ActorInitializer init) { return new FireWarheads(this); } + + public WeaponInfo[] WeaponInfos { get; private set; } + + public override void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + base.RulesetLoaded(rules, ai); + + WeaponInfos = Weapons.Select(w => + { + var weaponToLower = w.ToLowerInvariant(); + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) + throw new YamlException($"Weapons Ruleset does not contain an entry '{weaponToLower}'"); + return weapon; + }).ToArray(); + } + } + + public class FireWarheads : PausableConditionalTrait, ITick + { + [Sync] + int cooldown = 0; + + public FireWarheads(FireWarheadsInfo info) + : base(info) + { + cooldown = info.StartCooldown; + } + + void ITick.Tick(Actor self) + { + if (IsTraitDisabled || IsTraitPaused) + return; + + if (cooldown > 0) + cooldown--; + else + { + cooldown = Info.Interval; + foreach (var wep in Info.WeaponInfos) + { + wep.Impact(Target.FromPos(self.CenterPosition), self); + self.World.AddFrameEndTask(world => + { + if (wep.Report != null && wep.Report.Length > 0) + Game.Sound.Play(SoundType.World, wep.Report, world, self.CenterPosition); + }); + } + } + } + + protected override void TraitDisabled(Actor self) + { + cooldown = Info.StartCooldown; + } + } +} diff --git a/mods/ts/rules/gdi-vehicles.yaml b/mods/ts/rules/gdi-vehicles.yaml index 6c7abd7ea5..7b78764b41 100644 --- a/mods/ts/rules/gdi-vehicles.yaml +++ b/mods/ts/rules/gdi-vehicles.yaml @@ -425,3 +425,37 @@ JUGG: ArmamentNames: deployed Selectable: DecorationBounds: 1448, 2413, 0, -482 + +MOBILEMP: + Inherits: ^Tank + Inherits@VOXELS: ^VoxelActor + Inherits@selection: ^SelectableSupportUnit + Buildable: + Queue: Vehicle + BuildPaletteOrder: 130 + Prerequisites: ~gaweap, napuls, ~techlevel.superweapons + Description: Fires a pulse blast which disables\nall mechanical units in the area. + Valued: + Cost: 1000 + Tooltip: + Name: Mobile EMP Cannon + Health: + HP: 80000 + Armor: + Type: Heavy + Mobile: + Speed: 85 + WithVoxelBody: + Offset: 0,0,-256 + RevealsShroud: + RequiresCondition: !inside-tunnel + Range: 6c0 + MaxHeightDelta: 3 + GrantConditionOnDeployWithCharge: + Voice: Move + ChargeDuration: 750 + DeployedCondition: deployed + PauseOnCondition: empdisable + FireWarheads: + Weapons: MEMPulse + RequiresCondition: deployed && !empdisable diff --git a/mods/ts/rules/shared-support.yaml b/mods/ts/rules/shared-support.yaml index aa5673abbd..d34251b7e7 100644 --- a/mods/ts/rules/shared-support.yaml +++ b/mods/ts/rules/shared-support.yaml @@ -42,6 +42,9 @@ NAPULS: nod: napuls.nod ProvidesPrerequisite@gdi: ResetOnOwnerChange: true + ProvidesPrerequisite@gdi: + Factions: gdi + Prerequisite: napuls AttackOrderPower: PauseOnCondition: empdisable || disabled Cursor: emp diff --git a/mods/ts/sequences/misc.yaml b/mods/ts/sequences/misc.yaml index a31da521d7..ab452f8d16 100644 --- a/mods/ts/sequences/misc.yaml +++ b/mods/ts/sequences/misc.yaml @@ -212,6 +212,11 @@ explosion: BlendMode: Additive ZRamp: 1 Tick: 80 + pulse_explosion_small: + Filename: mempfx.shp + BlendMode: Additive + ZRamp: 1 + Tick: 11 small_watersplash: Filename: h2o_exp2.shp IgnoreWorldTint: False diff --git a/mods/ts/sequences/vehicles.yaml b/mods/ts/sequences/vehicles.yaml index 3bc7f7ce52..3e4af63734 100644 --- a/mods/ts/sequences/vehicles.yaml +++ b/mods/ts/sequences/vehicles.yaml @@ -338,6 +338,11 @@ smech: icon: Filename: smchicon.shp +mobilemp: + Inherits: ^VehicleOverlays + icon: + Filename: mempicon.shp + trucka: Inherits: ^VehicleOverlays diff --git a/mods/ts/sequences/voxels.yaml b/mods/ts/sequences/voxels.yaml index 8abcf3e9f2..6668ae05f9 100644 --- a/mods/ts/sequences/voxels.yaml +++ b/mods/ts/sequences/voxels.yaml @@ -120,6 +120,9 @@ sonic: idle: turret: sonictur +mobilemp: + idle: m_emp + #truk: # TODO: unused # idle: diff --git a/mods/ts/weapons/superweapons.yaml b/mods/ts/weapons/superweapons.yaml index e62ae6f171..789eebd526 100644 --- a/mods/ts/weapons/superweapons.yaml +++ b/mods/ts/weapons/superweapons.yaml @@ -127,3 +127,14 @@ EMPulseCannon: Duration: 250 Condition: empdisable ValidTargets: Ground, Water, Air, Underground + +MEMPulse: + Report: mobemp1.aud + Warhead@1Eff: CreateEffect + Explosions: pulse_explosion_small + ImpactActors: false + Warhead@emp: GrantExternalCondition + Range: 6c0 + Duration: 250 + Condition: empdisable + ValidTargets: Ground, Water, Air, Underground