From b4c826237ea8ff5fd3378b8bb5675ffceea972a3 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 26 Sep 2014 15:31:49 +1200 Subject: [PATCH 01/11] Remove duplicated IronCurtainable rules. --- mods/cnc/rules/defaults.yaml | 2 -- mods/ra/rules/aircraft.yaml | 12 ++---------- mods/ra/rules/defaults.yaml | 5 ++++- mods/ra/rules/ships.yaml | 6 ------ mods/ra/rules/structures.yaml | 30 ------------------------------ mods/ts/rules/structures.yaml | 2 -- 6 files changed, 6 insertions(+), 51 deletions(-) diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 977088e953..41364123bf 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -19,7 +19,6 @@ Chronoshiftable: Passenger: CargoType: Vehicle - IronCurtainable: HiddenUnderFog: GainsExperience: GivesExperience: @@ -70,7 +69,6 @@ Chronoshiftable: Passenger: CargoType: Vehicle - IronCurtainable: HiddenUnderFog: GainsExperience: GivesExperience: diff --git a/mods/ra/rules/aircraft.yaml b/mods/ra/rules/aircraft.yaml index f5787dfdf0..aa4d76f978 100644 --- a/mods/ra/rules/aircraft.yaml +++ b/mods/ra/rules/aircraft.yaml @@ -1,7 +1,7 @@ BADR: + Inherits: ^Plane ParaDrop: DropRange: 4c0 - Inherits: ^Plane Health: HP: 300 Armor: @@ -12,7 +12,6 @@ BADR: Repulsable: False RenderUnit: WithShadow: - IronCurtainable: Cargo: MaxWeight: 10 -Selectable: @@ -36,10 +35,10 @@ BADR: RejectsOrders: BADR.Bomber: + Inherits: ^Plane AttackBomber: Armament: Weapon: ParaBomb - Inherits: ^Plane Health: HP: 300 Armor: @@ -53,7 +52,6 @@ BADR.Bomber: RenderUnit: Image: badr WithShadow: - IronCurtainable: -Selectable: -GainsExperience: Tooltip: @@ -113,7 +111,6 @@ MIG: WithShadow: LimitedAmmo: Ammo: 8 - IronCurtainable: ReturnOnIdle: Selectable: Bounds: 40,29,0,1 @@ -173,7 +170,6 @@ YAK: Ammo: 18 PipCount: 6 ReloadTicks: 11 - IronCurtainable: ReturnOnIdle: Selectable: Bounds: 30,28,0,2 @@ -224,7 +220,6 @@ TRAN: Types: Infantry MaxWeight: 8 PipCount: 8 - IronCurtainable: LeavesHusk: HuskActor: TRAN.Husk @@ -270,7 +265,6 @@ HELI: WithShadow: LimitedAmmo: Ammo: 8 - IronCurtainable: Selectable: Bounds: 36,28,0,0 LeavesHusk: @@ -324,7 +318,6 @@ HIND: Ammo: 24 PipCount: 6 ReloadTicks: 8 - IronCurtainable: Selectable: Bounds: 38,32,0,0 WithMuzzleFlash: @@ -345,7 +338,6 @@ U2: Repulsable: False RenderUnit: WithShadow: - IronCurtainable: AttackBomber: -Selectable: -GainsExperience: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 7771b9f1f4..4fa5754fab 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -247,6 +247,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + IronCurtainable: ^Plane: AppearsOnRadar: @@ -290,6 +291,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + IronCurtainable: ^Helicopter: Inherits: ^Plane @@ -345,7 +347,8 @@ LuaScriptEvents: Demolishable: ScriptTriggers: - + IronCurtainable: + ^Defense: Inherits: ^Building TargetableBuilding: diff --git a/mods/ra/rules/ships.yaml b/mods/ra/rules/ships.yaml index 28534d6e4c..e384d9e1e4 100644 --- a/mods/ra/rules/ships.yaml +++ b/mods/ra/rules/ships.yaml @@ -38,7 +38,6 @@ SS: Selectable: Bounds: 38,38 Chronoshiftable: - IronCurtainable: RepairableNear: AutoTarget: InitialStance: ReturnFire @@ -90,7 +89,6 @@ MSUB: Selectable: Bounds: 44,44 Chronoshiftable: - IronCurtainable: RepairableNear: AutoTarget: InitialStance: ReturnFire @@ -141,7 +139,6 @@ DD: WithTurret: AutoTarget: Chronoshiftable: - IronCurtainable: RepairableNear: DetectCloaked: CloakTypes: Underwater @@ -206,7 +203,6 @@ CA: Turret: secondary AutoTarget: Chronoshiftable: - IronCurtainable: RepairableNear: Explodes: Weapon: UnitExplodeShip @@ -238,7 +234,6 @@ LST: Types: Infantry, Vehicle MaxWeight: 5 PipCount: 5 - IronCurtainable: RepairableNear: Explodes: Weapon: UnitExplodeShip @@ -284,7 +279,6 @@ PT: WithTurret: AutoTarget: Chronoshiftable: - IronCurtainable: RepairableNear: DetectCloaked: CloakTypes: Underwater diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index de58836ac8..363809b66e 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -19,7 +19,6 @@ MSLO: Type: Wood RevealsShroud: Range: 5c0 - IronCurtainable: NukePower: Icon: abomb ChargeTime: 540 @@ -75,7 +74,6 @@ GAP: HasMinibib: Yes CreatesShroud: Range: 6c0 - IronCurtainable: RenderShroudCircle: Power: Amount: -60 @@ -127,7 +125,6 @@ SPEN: Production: Produces: Ship, Submarine PrimaryBuilding: - IronCurtainable: -EmitInfantryOnSell: RepairsUnits: RallyPoint: @@ -181,7 +178,6 @@ SYRD: Production: Produces: Ship, Boat PrimaryBuilding: - IronCurtainable: -EmitInfantryOnSell: RepairsUnits: RallyPoint: @@ -217,7 +213,6 @@ IRON: Range: 10c0 Bib: HasMinibib: Yes - IronCurtainable: IronCurtainPower: Icon: invuln ChargeTime: 120 @@ -260,7 +255,6 @@ PDOX: Range: 10c0 Bib: HasMinibib: Yes - IronCurtainable: ChronoshiftPower: Icon: chrono ChargeTime: 120 @@ -314,7 +308,6 @@ TSLA: MaxCharges: 3 ReloadTime: 120 AutoTarget: - IronCurtainable: -RenderBuilding: RenderRangeCircle: -AcceptsSupplies: @@ -361,7 +354,6 @@ AGUN: AttackTurreted: WithMuzzleFlash: AutoTarget: - IronCurtainable: -RenderBuilding: RenderRangeCircle: RangeCircleType: aa @@ -399,7 +391,6 @@ DOME: Range: 10c0 Bib: ProvidesRadar: - IronCurtainable: InfiltrateForExploration: DetectCloaked: Range: 10 @@ -428,7 +419,6 @@ PBOX: Range: 6c0 Bib: HasMinibib: Yes - IronCurtainable: -AcceptsSupplies: Turreted: ROT: 255 @@ -476,7 +466,6 @@ HBOX: Cloak: InitialDelay: 125 CloakDelay: 60 - IronCurtainable: -AcceptsSupplies: Turreted: ROT: 255 @@ -534,7 +523,6 @@ GUN: AttackTurreted: WithMuzzleFlash: AutoTarget: - IronCurtainable: -RenderBuilding: RenderRangeCircle: -AcceptsSupplies: @@ -575,7 +563,6 @@ FTUR: BodyOrientation: QuantizedFacings: 8 AutoTarget: - IronCurtainable: RenderRangeCircle: -AcceptsSupplies: DrawLineToTarget: @@ -620,7 +607,6 @@ SAM: AttackTurreted: WithMuzzleFlash: AutoTarget: - IronCurtainable: -RenderBuilding: RenderRangeCircle: RangeCircleType: aa @@ -654,7 +640,6 @@ ATEK: RevealsShroud: Range: 10c0 Bib: - IronCurtainable: GpsPower: Icon: gps OneShot: yes @@ -712,7 +697,6 @@ WEAP: RequiresPrerequisites: structures.soviet Prerequisite: vehicles.soviet PrimaryBuilding: - IronCurtainable: ProductionBar: Power: Amount: -30 @@ -741,7 +725,6 @@ FACT: Bib: Production: Produces: Building,Defense - IronCurtainable: Valued: Cost: 2500 Tooltip: @@ -793,7 +776,6 @@ PROC: StoresResources: PipCount: 17 Capacity: 2000 - IronCurtainable: DrawLineToTarget: CustomSellValue: Value: 600 @@ -837,7 +819,6 @@ SILO: StoresResources: PipCount: 5 Capacity: 1500 - IronCurtainable: -RenderBuilding: -EmitInfantryOnSell: Power: @@ -872,7 +853,6 @@ HPAD: Production: Produces: Aircraft, Helicopter Reservable: - IronCurtainable: ProductionBar: PrimaryBuilding: Power: @@ -907,7 +887,6 @@ AFLD: Production: Produces: Aircraft, Plane Reservable: - IronCurtainable: AirstrikePower: Icon: spyplane ChargeTime: 180 @@ -962,7 +941,6 @@ POWR: RevealsShroud: Range: 4c0 Bib: - IronCurtainable: DeadBuildingState: Power: Amount: 100 @@ -996,7 +974,6 @@ APWR: RevealsShroud: Range: 4c0 Bib: - IronCurtainable: DeadBuildingState: Power: Amount: 200 @@ -1030,7 +1007,6 @@ STEK: RevealsShroud: Range: 4c0 Bib: - IronCurtainable: Power: Amount: -100 @@ -1065,7 +1041,6 @@ BARR: Production: Produces: Infantry, Soldier PrimaryBuilding: - IronCurtainable: ProductionBar: ProvidesCustomPrerequisite: Prerequisite: barracks @@ -1101,7 +1076,6 @@ KENN: Production: Produces: Infantry, Dog PrimaryBuilding: - IronCurtainable: ProductionBar: -EmitInfantryOnSell: Power: @@ -1138,7 +1112,6 @@ TENT: Production: Produces: Infantry, Soldier PrimaryBuilding: - IronCurtainable: ProductionBar: ProvidesCustomPrerequisite: Prerequisite: barracks @@ -1169,7 +1142,6 @@ FIX: HasMinibib: Yes Reservable: RallyPoint: - IronCurtainable: RepairsUnits: Interval: 10 WithRepairAnimation: @@ -1200,7 +1172,6 @@ FACF: RenderBuilding: Image: FACT Fake: - IronCurtainable: -EmitInfantryOnSell: Power: Amount: -2 @@ -1231,7 +1202,6 @@ WEAF: RenderBuildingWarFactory: Image: WEAP Fake: - IronCurtainable: -EmitInfantryOnSell: Power: Amount: -2 diff --git a/mods/ts/rules/structures.yaml b/mods/ts/rules/structures.yaml index e639c11e81..94a831c7a0 100644 --- a/mods/ts/rules/structures.yaml +++ b/mods/ts/rules/structures.yaml @@ -113,7 +113,6 @@ GAPILE: Production: Produces: Infantry PrimaryBuilding: - IronCurtainable: ProductionBar: WithProductionOverlay@LIGHTS: Sequence: production-lights @@ -338,7 +337,6 @@ NAHAND: Production: Produces: Infantry PrimaryBuilding: - IronCurtainable: ProductionBar: WithIdleOverlay@LIGHTS: Sequence: idle-lights From c697a1e7b4488a8d0f2998047aca919a30315253 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 26 Sep 2014 13:02:34 +1200 Subject: [PATCH 02/11] Add a UnitUpgradeManager trait. This introduces support for timed upgrades, starting with crate buffs. --- .../UtilityCommands/UpgradeRules.cs | 7 + .../Crates/UnitUpgradeCrateAction.cs | 50 +++---- OpenRA.Mods.RA/GainsExperience.cs | 6 +- OpenRA.Mods.RA/GlobalUpgradable.cs | 24 ++-- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 7 + OpenRA.Mods.RA/TimedUpgradeBar.cs | 58 ++++++++ OpenRA.Mods.RA/UpgradeManager.cs | 134 ++++++++++++++++++ mods/cnc/rules/defaults.yaml | 6 + mods/d2k/rules/defaults.yaml | 4 + mods/ra/rules/defaults.yaml | 6 + mods/ts/rules/defaults.yaml | 4 + 11 files changed, 268 insertions(+), 38 deletions(-) create mode 100644 OpenRA.Mods.RA/TimedUpgradeBar.cs create mode 100644 OpenRA.Mods.RA/UpgradeManager.cs diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 3296d68e50..15aaec6864 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -575,6 +575,13 @@ namespace OpenRA.Mods.Common.UtilityCommands } } + // Routed unit upgrades via the UnitUpgradeManager trait + if (engineVersion < 20141001) + { + if (depth == 0 && node.Value.Nodes.Any(n => n.Key.StartsWith("GainsStatUpgrades"))) + node.Value.Nodes.Add(new MiniYamlNode("UnitUpgradeManager", new MiniYaml(""))); + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } } diff --git a/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs b/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs index 55543da2b3..47228af0ea 100644 --- a/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs @@ -16,9 +16,12 @@ namespace OpenRA.Mods.RA.Crates [Desc("Grants an upgrade to the collector.")] public class UnitUpgradeCrateActionInfo : CrateActionInfo { - [Desc("The upgrade to grant.")] + [Desc("The upgrades to apply.")] public readonly string[] Upgrades = { }; + [Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent upgrade.")] + public readonly int Duration = 0; + [Desc("The range to search for extra collectors in.", "Extra collectors will also be granted the crate action.")] public readonly WRange Range = new WRange(3); @@ -42,16 +45,8 @@ namespace OpenRA.Mods.RA.Crates bool AcceptsUpgrade(Actor a) { - return a.TraitsImplementing() - .Any(up => info.Upgrades.Any(u => up.AcceptsUpgrade(u))); - } - - void GrantActorUpgrades(Actor a) - { - foreach (var up in a.TraitsImplementing()) - foreach (var u in info.Upgrades) - if (up.AcceptsUpgrade(u)) - up.UpgradeAvailable(a, u, true); + var um = a.TraitOrDefault(); + return um != null && info.Upgrades.Any(u => um.AcceptsUpgrade(a, u)); } public override int GetSelectionShares(Actor collector) @@ -61,25 +56,32 @@ namespace OpenRA.Mods.RA.Crates public override void Activate(Actor collector) { - collector.World.AddFrameEndTask(w => GrantActorUpgrades(collector)); - var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, info.Range) - .Where(a => a != self && a.Owner == collector.Owner && AcceptsUpgrade(a)); + .Where(a => a != self && a != collector && a.Owner == collector.Owner && AcceptsUpgrade(a)); - if (actorsInRange.Any()) + if (info.MaxExtraCollectors > -1) + actorsInRange = actorsInRange.Take(info.MaxExtraCollectors); + + collector.World.AddFrameEndTask(w => { - if (info.MaxExtraCollectors > -1) - actorsInRange = actorsInRange.Take(info.MaxExtraCollectors); - - collector.World.AddFrameEndTask(w => + foreach (var a in actorsInRange.Append(collector)) { - foreach (var a in actorsInRange) + if (!a.IsInWorld || a.IsDead()) + continue; + + var um = a.TraitOrDefault(); + foreach (var u in info.Upgrades) { - if (!a.IsDead() && a.IsInWorld) - GrantActorUpgrades(a); + if (!um.AcceptsUpgrade(a, u)) + continue; + + if (info.Duration > 0) + um.GrantTimedUpgrade(a, u, info.Duration); + else + um.GrantUpgrade(a, u, this); } - }); - } + } + }); base.Activate(collector); } diff --git a/OpenRA.Mods.RA/GainsExperience.cs b/OpenRA.Mods.RA/GainsExperience.cs index 92f1e34aae..c1c88d1736 100644 --- a/OpenRA.Mods.RA/GainsExperience.cs +++ b/OpenRA.Mods.RA/GainsExperience.cs @@ -102,10 +102,10 @@ namespace OpenRA.Mods.RA Level++; - foreach (var up in self.TraitsImplementing()) + var um = self.TraitOrDefault(); + if (um != null) foreach (var u in upgrades) - if (up.AcceptsUpgrade(u)) - up.UpgradeAvailable(self, u, true); + um.GrantUpgrade(self, u, this); Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Sounds", "LevelUp", self.Owner.Country.Race); self.World.AddFrameEndTask(w => w.Add(new CrateEffect(self, "levelup", info.LevelUpPalette))); diff --git a/OpenRA.Mods.RA/GlobalUpgradable.cs b/OpenRA.Mods.RA/GlobalUpgradable.cs index 021fd90c5c..a38da1f9cd 100644 --- a/OpenRA.Mods.RA/GlobalUpgradable.cs +++ b/OpenRA.Mods.RA/GlobalUpgradable.cs @@ -17,7 +17,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - public class GlobalUpgradableInfo : ITraitInfo + public class GlobalUpgradableInfo : ITraitInfo, Requires { public readonly string[] Upgrades = { }; public readonly string[] Prerequisites = { }; @@ -28,34 +28,36 @@ namespace OpenRA.Mods.RA public class GlobalUpgradable : INotifyAddedToWorld, INotifyRemovedFromWorld { readonly GlobalUpgradableInfo info; - readonly GlobalUpgradeManager manager; + readonly GlobalUpgradeManager globalManager; + readonly UpgradeManager manager; - public GlobalUpgradable(Actor actor, GlobalUpgradableInfo info) + public GlobalUpgradable(Actor self, GlobalUpgradableInfo info) { this.info = info; - manager = actor.Owner.PlayerActor.Trait(); + globalManager = self.Owner.PlayerActor.Trait(); + manager = self.Trait(); } public void AddedToWorld(Actor self) { if (info.Prerequisites.Any()) - manager.Register(self, this, info.Prerequisites); + globalManager.Register(self, this, info.Prerequisites); } public void RemovedFromWorld(Actor self) { if (info.Prerequisites.Any()) - manager.Unregister(self, this, info.Prerequisites); + globalManager.Unregister(self, this, info.Prerequisites); } public void PrerequisitesUpdated(Actor self, bool available) { - var upgrades = self.TraitsImplementing(); - foreach (var u in upgrades) + foreach (var u in info.Upgrades) { - foreach (var t in info.Upgrades) - if (u.AcceptsUpgrade(t)) - u.UpgradeAvailable(self, t, available); + if (available) + manager.GrantUpgrade(self, u, this); + else + manager.RevokeUpgrade(self, u, this); } } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 1401a4b0a2..cd7ccb0fed 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -564,6 +564,13 @@ + + + + + + + diff --git a/OpenRA.Mods.RA/TimedUpgradeBar.cs b/OpenRA.Mods.RA/TimedUpgradeBar.cs new file mode 100644 index 0000000000..b4f2cc56d6 --- /dev/null +++ b/OpenRA.Mods.RA/TimedUpgradeBar.cs @@ -0,0 +1,58 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Drawing; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + [Desc("Visualizes the remaining time for an upgrade.")] + class TimedUpgradeBarInfo : ITraitInfo, Requires + { + [Desc("Upgrade that this bar corresponds to")] + public readonly string Upgrade = null; + + public readonly Color Color = Color.Red; + + public object Create(ActorInitializer init) { return new TimedUpgradeBar(init.self, this); } + } + + class TimedUpgradeBar : ISelectionBar + { + readonly TimedUpgradeBarInfo info; + readonly Actor self; + float value; + + public TimedUpgradeBar(Actor self, TimedUpgradeBarInfo info) + { + this.self = self; + this.info = info; + + self.Trait().RegisterWatcher(info.Upgrade, Update); + } + + public void Update(int duration, int remaining) + { + value = remaining * 1f / duration; + } + + public float GetValue() + { + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) + return 0; + + return value; + } + + public Color GetColor() { return info.Color; } + } +} diff --git a/OpenRA.Mods.RA/UpgradeManager.cs b/OpenRA.Mods.RA/UpgradeManager.cs new file mode 100644 index 0000000000..c72fd48155 --- /dev/null +++ b/OpenRA.Mods.RA/UpgradeManager.cs @@ -0,0 +1,134 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class UpgradeManagerInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new UpgradeManager(init); } + } + + public class UpgradeManager : ITick + { + class TimedUpgrade + { + public readonly string Upgrade; + public readonly int Duration; + public int Remaining; + + public TimedUpgrade(string upgrade, int duration) + { + Upgrade = upgrade; + Duration = duration; + Remaining = duration; + } + + public void Tick() { Remaining--; } + } + + readonly List timedUpgrades = new List(); + readonly Dictionary> sources = new Dictionary>(); + readonly Dictionary>> watchers = new Dictionary>>(); + readonly Lazy> upgradable; + + public UpgradeManager(ActorInitializer init) + { + upgradable = Exts.Lazy(() => init.self.TraitsImplementing()); + } + + public void GrantTimedUpgrade(Actor self, string upgrade, int duration) + { + var timed = timedUpgrades.FirstOrDefault(u => u.Upgrade == upgrade); + if (timed == null) + { + timed = new TimedUpgrade(upgrade, duration); + timedUpgrades.Add(timed); + GrantUpgrade(self, upgrade, timed); + } + else + timed.Remaining = Math.Max(duration, timed.Remaining); + } + + public void GrantUpgrade(Actor self, string upgrade, object source) + { + List ss; + if (!sources.TryGetValue(upgrade, out ss)) + { + ss = new List(); + sources.Add(upgrade, ss); + + foreach (var up in upgradable.Value) + if (up.AcceptsUpgrade(upgrade)) + up.UpgradeAvailable(self, upgrade, true); + } + + // Track the upgrade source so that the upgrade can be removed without conflicts + ss.Add(source); + } + + public void RevokeUpgrade(Actor self, string upgrade, object source) + { + // This upgrade may have been granted by multiple sources + // We must be careful to only remove the upgrade after all + // sources have been revoked + List ss; + if (!sources.TryGetValue(upgrade, out ss)) + return; + + ss.Remove(source); + if (!ss.Any()) + { + foreach (var up in upgradable.Value) + if (up.AcceptsUpgrade(upgrade)) + up.UpgradeAvailable(self, upgrade, false); + + sources.Remove(upgrade); + } + } + + public bool AcceptsUpgrade(Actor self, string upgrade) + { + return upgradable.Value.Any(up => up.AcceptsUpgrade(upgrade)); + } + + public void RegisterWatcher(string upgrade, Action action) + { + if (!watchers.ContainsKey(upgrade)) + watchers.Add(upgrade, new List>()); + + watchers[upgrade].Add(action); + } + + public void Tick(Actor self) + { + foreach (var u in timedUpgrades) + { + u.Tick(); + if (u.Remaining <= 0) + RevokeUpgrade(self, u.Upgrade, u); + + List> actions; + if (watchers.TryGetValue(u.Upgrade, out actions)) + foreach (var a in actions) + a(u.Duration, u.Remaining); + } + + timedUpgrades.RemoveAll(u => u.Remaining <= 0); + } + } +} diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 41364123bf..c7cf54016a 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -47,6 +47,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Tank: AppearsOnRadar: @@ -100,6 +101,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Helicopter: AppearsOnRadar: @@ -138,6 +140,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Infantry: AppearsOnRadar: @@ -218,6 +221,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^CivInfantry: Inherits: ^Infantry @@ -324,6 +328,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Ship: AppearsOnRadar: @@ -357,6 +362,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Building: AppearsOnRadar: diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index eda438f6c8..f0db34c4c1 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -46,6 +46,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Tank: AppearsOnRadar: @@ -95,6 +96,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Husk: Health: @@ -221,6 +223,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Plane: AppearsOnRadar: @@ -253,6 +256,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Helicopter: Inherits: ^Plane diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 4fa5754fab..53158a0255 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -60,6 +60,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Tank: AppearsOnRadar: @@ -123,6 +124,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Infantry: AppearsOnRadar: @@ -207,6 +209,7 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal + UpgradeManager: ^Ship: AppearsOnRadar: @@ -248,6 +251,7 @@ DamageCooldown: 125 RequiresUpgrade: selfheal IronCurtainable: + UpgradeManager: ^Plane: AppearsOnRadar: @@ -292,6 +296,7 @@ DamageCooldown: 125 RequiresUpgrade: selfheal IronCurtainable: + UpgradeManager: ^Helicopter: Inherits: ^Plane @@ -348,6 +353,7 @@ Demolishable: ScriptTriggers: IronCurtainable: + UpgradeManager: ^Defense: Inherits: ^Building diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index 101b64c0e1..18d25dab0f 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -157,6 +157,7 @@ DeathSounds@ZAPPED: DeathSound: Zapped DeathTypes: 6 + UpgradeManager: ^CivilianInfantry: Inherits: ^Infantry @@ -243,6 +244,7 @@ Explodes: Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall + UpgradeManager: ^Tank: AppearsOnRadar: @@ -302,6 +304,7 @@ Explodes: Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall + UpgradeManager: ^Helicopter: AppearsOnRadar: @@ -348,6 +351,7 @@ ScriptTriggers: Guard: Guardable: + UpgradeManager: ^BlossomTree: Tooltip: From 331f2852db97e36af421f316b1706656d747d101 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 26 Sep 2014 14:35:16 +1200 Subject: [PATCH 03/11] Fix cloak upgrade expiration. --- OpenRA.Mods.RA/Cloak.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/OpenRA.Mods.RA/Cloak.cs b/OpenRA.Mods.RA/Cloak.cs index 4cfcddd609..ef673e0659 100644 --- a/OpenRA.Mods.RA/Cloak.cs +++ b/OpenRA.Mods.RA/Cloak.cs @@ -71,7 +71,15 @@ namespace OpenRA.Mods.RA public void UpgradeAvailable(Actor self, string type, bool available) { if (type == Info.RequiresUpgrade) + { disabled = !available; + + if (disabled) + { + Uncloak(); + remainingTime = Info.InitialDelay; + } + } } public void Uncloak() { Uncloak(Info.CloakDelay); } @@ -86,7 +94,7 @@ namespace OpenRA.Mods.RA public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { if (Info.UncloakOnAttack) Uncloak(); } - public bool Cloaked { get { return remainingTime <= 0; } } + public bool Cloaked { get { return !disabled && remainingTime <= 0; } } public void DamageStateChanged(Actor self, AttackInfo e) { @@ -97,20 +105,25 @@ namespace OpenRA.Mods.RA public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { - if (remainingTime > 0) + if (remainingTime > 0 || disabled) return r; if (Cloaked && IsVisible(self, self.World.RenderPlayer)) + { if (string.IsNullOrEmpty(Info.Palette)) return r; else return r.Select(a => a.WithPalette(wr.Palette(Info.Palette))); + } else return SpriteRenderable.None; } public void Tick(Actor self) { + if (disabled) + return; + if (remainingTime > 0 && !disabled && !damageDisabled && --remainingTime <= 0) Sound.Play(Info.CloakSound, self.CenterPosition); From 968486a03ea6c9d1206e1db717453e2518492650 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 26 Sep 2014 15:17:30 +1200 Subject: [PATCH 04/11] Reimplement iron curtain as a generic stat upgrade. --- .../UtilityCommands/UpgradeRules.cs | 42 +++++++++++- OpenRA.Mods.RA/Effects/InvulnEffect.cs | 44 ------------- OpenRA.Mods.RA/InvulnerabilityUpgrade.cs | 51 +++++++++++++++ OpenRA.Mods.RA/IronCurtainable.cs | 55 ---------------- OpenRA.Mods.RA/Modifiers/UpgradeOverlay.cs | 63 ++++++++++++++++++ OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 3 - ...onCurtainPower.cs => GrantUpgradePower.cs} | 65 +++++++++++++------ mods/ra/maps/bomber-john/map.yaml | 10 +-- mods/ra/rules/defaults.yaml | 35 ++++++++-- mods/ra/rules/structures.yaml | 5 +- mods/ra/rules/vehicles.yaml | 2 +- 11 files changed, 240 insertions(+), 135 deletions(-) delete mode 100644 OpenRA.Mods.RA/Effects/InvulnEffect.cs create mode 100644 OpenRA.Mods.RA/InvulnerabilityUpgrade.cs delete mode 100644 OpenRA.Mods.RA/IronCurtainable.cs create mode 100644 OpenRA.Mods.RA/Modifiers/UpgradeOverlay.cs rename OpenRA.Mods.RA/SupportPowers/{IronCurtainPower.cs => GrantUpgradePower.cs} (66%) diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 15aaec6864..872f2a56de 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -575,11 +575,51 @@ namespace OpenRA.Mods.Common.UtilityCommands } } - // Routed unit upgrades via the UnitUpgradeManager trait if (engineVersion < 20141001) { + // Routed unit upgrades via the UnitUpgradeManager trait if (depth == 0 && node.Value.Nodes.Any(n => n.Key.StartsWith("GainsStatUpgrades"))) node.Value.Nodes.Add(new MiniYamlNode("UnitUpgradeManager", new MiniYaml(""))); + + // Replaced IronCurtainPower -> GrantUpgradePower + if (depth == 1 && node.Key == "IronCurtainPower") + { + node.Key = "GrantUpgradePower@IRONCURTAIN"; + node.Value.Nodes.Add(new MiniYamlNode("Upgrades", "invulnerability")); + + var durationNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Duration"); + if (durationNode != null) + durationNode.Value.Value = (int.Parse(durationNode.Value.Value) * 25).ToString(); + else + node.Value.Nodes.Add(new MiniYamlNode("Duration", "600")); + + var soundNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "IronCurtainSound"); + if (soundNode != null) + soundNode.Key = "GrantUpgradeSound"; + } + + if (depth == 0 && node.Value.Nodes.Any(n => n.Key.StartsWith("IronCurtainable"))) + { + node.Value.Nodes.RemoveAll(n => n.Key.StartsWith("IronCurtainable")); + + var overlayKeys = new List(); + overlayKeys.Add(new MiniYamlNode("RequiresUpgrade", "invulnerability")); + node.Value.Nodes.Add(new MiniYamlNode("UpgradeOverlay@IRONCURTAIN", new MiniYaml("", overlayKeys))); + + var invulnKeys = new List(); + invulnKeys.Add(new MiniYamlNode("RequiresUpgrade", "invulnerability")); + node.Value.Nodes.Add(new MiniYamlNode("InvulnerabilityUpgrade@IRONCURTAIN", new MiniYaml("", invulnKeys))); + + var barKeys = new List(); + barKeys.Add(new MiniYamlNode("Upgrade", "invulnerability")); + node.Value.Nodes.Add(new MiniYamlNode("TimedUpgradeBar", new MiniYaml("", barKeys))); + + if (!node.Value.Nodes.Any(n => n.Key.StartsWith("UnitUpgradeManager"))) + node.Value.Nodes.Add(new MiniYamlNode("UnitUpgradeManager", new MiniYaml(""))); + } + + if (depth == 1 && node.Key == "-IronCurtainable") + node.Key = "-InvulnerabilityUpgrade@IRONCURTAIN"; } UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); diff --git a/OpenRA.Mods.RA/Effects/InvulnEffect.cs b/OpenRA.Mods.RA/Effects/InvulnEffect.cs deleted file mode 100644 index da804ea74f..0000000000 --- a/OpenRA.Mods.RA/Effects/InvulnEffect.cs +++ /dev/null @@ -1,44 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2014 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 OpenRA.Effects; -using OpenRA.Graphics; - -namespace OpenRA.Mods.RA.Effects -{ - class InvulnEffect : IEffect - { - Actor a; - IronCurtainable b; - - public InvulnEffect(Actor a) - { - this.a = a; - this.b = a.Trait(); - } - - public void Tick( World world ) - { - if (a.IsDead() || b.GetDamageModifier(null, null) > 0) - world.AddFrameEndTask(w => w.Remove(this)); - } - - public IEnumerable Render(WorldRenderer wr) - { - if (a.Destroyed) // Tick will clean up - yield break; - - foreach (var r in a.Render(wr)) - if (!r.IsDecoration) - yield return r.WithPalette(wr.Palette("invuln")); - } - } -} diff --git a/OpenRA.Mods.RA/InvulnerabilityUpgrade.cs b/OpenRA.Mods.RA/InvulnerabilityUpgrade.cs new file mode 100644 index 0000000000..ffa34449a3 --- /dev/null +++ b/OpenRA.Mods.RA/InvulnerabilityUpgrade.cs @@ -0,0 +1,51 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class InvulnerabilityUpgradeInfo : ITraitInfo + { + public readonly string RequiresUpgrade = "invulnerability"; + + public object Create(ActorInitializer init) { return new InvulnerabilityUpgrade(this); } + } + + public class InvulnerabilityUpgrade : IUpgradable, IDamageModifier + { + readonly InvulnerabilityUpgradeInfo info; + bool enabled; + + public InvulnerabilityUpgrade(InvulnerabilityUpgradeInfo info) + { + this.info = info; + } + + public bool AcceptsUpgrade(string type) + { + return type == info.RequiresUpgrade; + } + + public void UpgradeAvailable(Actor self, string type, bool available) + { + if (type == info.RequiresUpgrade) + enabled = available; + } + + public int GetDamageModifier(Actor attacker, DamageWarhead warhead) + { + return enabled ? 0 : 100; + } + } +} diff --git a/OpenRA.Mods.RA/IronCurtainable.cs b/OpenRA.Mods.RA/IronCurtainable.cs deleted file mode 100644 index 8fae33fc2b..0000000000 --- a/OpenRA.Mods.RA/IronCurtainable.cs +++ /dev/null @@ -1,55 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2014 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.Drawing; -using OpenRA.GameRules; -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class IronCurtainableInfo : TraitInfo { } - - class IronCurtainable : IDamageModifier, ITick, ISync, ISelectionBar - { - [Sync] int RemainingTicks = 0; - int TotalTicks; - - public void Tick(Actor self) - { - if (RemainingTicks > 0) - RemainingTicks--; - } - - public int GetDamageModifier(Actor attacker, DamageWarhead warhead) - { - return RemainingTicks > 0 ? 0 : 100; - } - - public void Activate(Actor self, int duration) - { - if (RemainingTicks == 0) - self.World.AddFrameEndTask(w => w.Add(new InvulnEffect(self))); // do not stack the invuln effect - - RemainingTicks = duration; - TotalTicks = duration; - } - - // Show the remaining time as a bar - public float GetValue() - { - if (RemainingTicks == 0) // otherwise an empty bar is rendered all the time - return 0f; - - return (float)RemainingTicks / TotalTicks; - } - public Color GetColor() { return Color.Red; } - } -} \ No newline at end of file diff --git a/OpenRA.Mods.RA/Modifiers/UpgradeOverlay.cs b/OpenRA.Mods.RA/Modifiers/UpgradeOverlay.cs new file mode 100644 index 0000000000..2443df4b76 --- /dev/null +++ b/OpenRA.Mods.RA/Modifiers/UpgradeOverlay.cs @@ -0,0 +1,63 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + [Desc("Display a colored overlay when a timed upgrade is active.")] + public class UpgradeOverlayInfo : ITraitInfo + { + [Desc("Upgrade that is required before this overlay is rendered")] + public readonly string RequiresUpgrade = null; + + [Desc("Palette to use when rendering the overlay")] + public readonly string Palette = "invuln"; + + public object Create(ActorInitializer init) { return new UpgradeOverlay(this); } + } + + public class UpgradeOverlay : IRenderModifier, IUpgradable + { + readonly UpgradeOverlayInfo info; + bool enabled; + + public UpgradeOverlay(UpgradeOverlayInfo info) + { + this.info = info; + } + + public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) + { + foreach (var a in r) + { + yield return a; + + if (enabled && !a.IsDecoration) + yield return a.WithPalette(wr.Palette(info.Palette)) + .WithZOffset(a.ZOffset + 1) + .AsDecoration(); + } + } + + public bool AcceptsUpgrade(string type) + { + return type == info.RequiresUpgrade; + } + + public void UpgradeAvailable(Actor self, string type, bool available) + { + if (type == info.RequiresUpgrade) + enabled = available; + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index cd7ccb0fed..ca87819c27 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -220,7 +220,6 @@ - @@ -245,7 +244,6 @@ - @@ -359,7 +357,6 @@ - diff --git a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs b/OpenRA.Mods.RA/SupportPowers/GrantUpgradePower.cs similarity index 66% rename from OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs rename to OpenRA.Mods.RA/SupportPowers/GrantUpgradePower.cs index e0ba5b4003..c2003e6fc9 100644 --- a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/GrantUpgradePower.cs @@ -17,22 +17,27 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - class IronCurtainPowerInfo : SupportPowerInfo + class GrantUpgradePowerInfo : SupportPowerInfo { - [Desc("Seconds")] - public readonly int Duration = 10; + [Desc("The upgrades to apply.")] + public readonly string[] Upgrades = { }; + + [Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent upgrade.")] + public readonly int Duration = 0; + [Desc("Cells")] public readonly int Range = 1; - public readonly string IronCurtainSound = "ironcur9.aud"; + public readonly string GrantUpgradeSound = "ironcur9.aud"; - public override object Create(ActorInitializer init) { return new IronCurtainPower(init.self, this); } + public override object Create(ActorInitializer init) { return new GrantUpgradePower(init.self, this); } } - class IronCurtainPower : SupportPower + class GrantUpgradePower : SupportPower { - IronCurtainPowerInfo info; + GrantUpgradePowerInfo info; - public IronCurtainPower(Actor self, IronCurtainPowerInfo info) : base(self, info) + public GrantUpgradePower(Actor self, GrantUpgradePowerInfo info) + : base(self, info) { this.info = info; } @@ -49,38 +54,59 @@ namespace OpenRA.Mods.RA self.Trait().PlayCustomAnim(self, "active"); - Sound.Play(info.IronCurtainSound, self.World.Map.CenterOfCell(order.TargetLocation)); + Sound.Play(info.GrantUpgradeSound, self.World.Map.CenterOfCell(order.TargetLocation)); - foreach (var target in UnitsInRange(order.TargetLocation) - .Where(a => a.Owner.Stances[self.Owner] == Stance.Ally)) - target.Trait().Activate(target, ((IronCurtainPowerInfo)Info).Duration * 25); + foreach (var a in UnitsInRange(order.TargetLocation)) + { + var um = a.TraitOrDefault(); + if (um == null) + continue; + + foreach (var u in info.Upgrades) + { + if (!um.AcceptsUpgrade(a, u)) + continue; + + if (info.Duration > 0) + um.GrantTimedUpgrade(a, u, info.Duration); + else + um.GrantUpgrade(a, u, this); + } + } } public IEnumerable UnitsInRange(CPos xy) { - var range = ((IronCurtainPowerInfo)Info).Range; + var range = info.Range; var tiles = self.World.Map.FindTilesInCircle(xy, range); var units = new List(); foreach (var t in tiles) units.AddRange(self.World.ActorMap.GetUnitsAt(t)); - return units.Distinct().Where(a => a.HasTrait()); + return units.Distinct().Where(a => + { + if (!a.Owner.IsAlliedWith(self.Owner)) + return false; + + var um = a.TraitOrDefault(); + return um != null && info.Upgrades.Any(u => um.AcceptsUpgrade(a, u)); + }); } class SelectTarget : IOrderGenerator { - readonly IronCurtainPower power; + readonly GrantUpgradePower power; readonly int range; readonly Sprite tile; readonly SupportPowerManager manager; readonly string order; - public SelectTarget(World world, string order, SupportPowerManager manager, IronCurtainPower power) + public SelectTarget(World world, string order, SupportPowerManager manager, GrantUpgradePower power) { this.manager = manager; this.order = order; this.power = power; - this.range = ((IronCurtainPowerInfo)power.Info).Range; + this.range = power.info.Range; tile = world.Map.SequenceProvider.GetSequence("overlay", "target-select").GetSprite(0); } @@ -101,8 +127,7 @@ namespace OpenRA.Mods.RA public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); - var targetUnits = power.UnitsInRange(xy).Where(a => a.Owner.Stances[power.self.Owner] == Stance.Ally); - foreach (var unit in targetUnits) + foreach (var unit in power.UnitsInRange(xy)) yield return new SelectionBoxRenderable(unit, Color.Red); } @@ -117,7 +142,7 @@ namespace OpenRA.Mods.RA public string GetCursor(World world, CPos xy, MouseInput mi) { - return power.UnitsInRange(xy).Any(a => a.Owner.Stances[power.self.Owner] == Stance.Ally) ? "ability" : "move-blocked"; + return power.UnitsInRange(xy).Any() ? "ability" : "move-blocked"; } } } diff --git a/mods/ra/maps/bomber-john/map.yaml b/mods/ra/maps/bomber-john/map.yaml index abcccc4bb3..3434f0f84f 100644 --- a/mods/ra/maps/bomber-john/map.yaml +++ b/mods/ra/maps/bomber-john/map.yaml @@ -862,16 +862,17 @@ Rules: Duration: 999999 KillCargo: yes Range: 3 - IronCurtainPower: + GrantUpgradePower@IRONCURTAIN: Icon: invuln ChargeTime: 30 Description: Invulnerability LongDesc: Makes a unit invulnerable\nfor 3 seconds. - Duration: 3 + Duration: 75 SelectTargetSound: slcttgt1.aud BeginChargeSound: ironchg1.aud EndChargeSound: ironrdy1.aud Range: 1 + Upgrades: invulnerability Power: Amount: 0 MINVV: @@ -928,16 +929,17 @@ Rules: Duration: 999999 KillCargo: yes Range: 3 - IronCurtainPower: + GrantUpgradePower@IRONCURTAIN: Icon: invuln ChargeTime: 30 Description: Invulnerability LongDesc: Makes a unit invulnerable\nfor 3 seconds. - Duration: 3 + Duration: 75 SelectTargetSound: slcttgt1.aud BeginChargeSound: ironchg1.aud EndChargeSound: ironrdy1.aud Range: 1 + Upgrades: invulnerability Sequences: miner: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 53158a0255..4d251eb0d3 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -20,7 +20,6 @@ Chronoshiftable: Passenger: CargoType: Vehicle - IronCurtainable: AttackMove: HiddenUnderFog: GainsExperience: @@ -61,6 +60,12 @@ DamageCooldown: 125 RequiresUpgrade: selfheal UpgradeManager: + UpgradeOverlay@IRONCURTAIN: + RequiresUpgrade: invulnerability + InvulnerabilityUpgrade@IRONCURTAIN: + RequiresUpgrade: invulnerability + TimedUpgradeBar: + Upgrade: invulnerability ^Tank: AppearsOnRadar: @@ -84,7 +89,6 @@ Chronoshiftable: Passenger: CargoType: Vehicle - IronCurtainable: AttackMove: HiddenUnderFog: GainsExperience: @@ -125,6 +129,12 @@ DamageCooldown: 125 RequiresUpgrade: selfheal UpgradeManager: + UpgradeOverlay@IRONCURTAIN: + RequiresUpgrade: invulnerability + InvulnerabilityUpgrade@IRONCURTAIN: + RequiresUpgrade: invulnerability + TimedUpgradeBar: + Upgrade: invulnerability ^Infantry: AppearsOnRadar: @@ -250,8 +260,13 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal - IronCurtainable: UpgradeManager: + UpgradeOverlay@IRONCURTAIN: + RequiresUpgrade: invulnerability + InvulnerabilityUpgrade@IRONCURTAIN: + RequiresUpgrade: invulnerability + TimedUpgradeBar: + Upgrade: invulnerability ^Plane: AppearsOnRadar: @@ -295,8 +310,13 @@ HealIfBelow: 1 DamageCooldown: 125 RequiresUpgrade: selfheal - IronCurtainable: UpgradeManager: + UpgradeOverlay@IRONCURTAIN: + RequiresUpgrade: invulnerability + InvulnerabilityUpgrade@IRONCURTAIN: + RequiresUpgrade: invulnerability + TimedUpgradeBar: + Upgrade: invulnerability ^Helicopter: Inherits: ^Plane @@ -352,8 +372,13 @@ LuaScriptEvents: Demolishable: ScriptTriggers: - IronCurtainable: UpgradeManager: + UpgradeOverlay@IRONCURTAIN: + RequiresUpgrade: invulnerability + InvulnerabilityUpgrade@IRONCURTAIN: + RequiresUpgrade: invulnerability + TimedUpgradeBar: + Upgrade: invulnerability ^Defense: Inherits: ^Building diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 363809b66e..02266ff5c2 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -213,17 +213,18 @@ IRON: Range: 10c0 Bib: HasMinibib: Yes - IronCurtainPower: + GrantUpgradePower@IRONCURTAIN: Icon: invuln ChargeTime: 120 Description: Invulnerability LongDesc: Makes a group of units invulnerable\nfor 20 seconds. - Duration: 20 + Duration: 500 SelectTargetSound: slcttgt1.aud InsufficientPowerSound: nopowr1.aud BeginChargeSound: ironchg1.aud EndChargeSound: ironrdy1.aud DisplayRadarPing: True + Upgrades: invulnerability SupportPowerChargeBar: Power: Amount: -200 diff --git a/mods/ra/rules/vehicles.yaml b/mods/ra/rules/vehicles.yaml index c804276bf6..6e4e7752c1 100644 --- a/mods/ra/rules/vehicles.yaml +++ b/mods/ra/rules/vehicles.yaml @@ -651,7 +651,7 @@ DTRK: Weapon: MiniNuke EmptyWeapon: MiniNuke DemoTruck: - -IronCurtainable: + -InvulnerabilityUpgrade@IRONCURTAIN: Chronoshiftable: ExplodeInstead: yes From a03305762f1254b35444e385d952d83902e2d636 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 26 Sep 2014 16:45:28 +1200 Subject: [PATCH 05/11] Add the invulnerability crate to RA. --- mods/ra/rules/misc.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mods/ra/rules/misc.yaml b/mods/ra/rules/misc.yaml index 7f425f469f..2dd34bf0fe 100644 --- a/mods/ra/rules/misc.yaml +++ b/mods/ra/rules/misc.yaml @@ -147,6 +147,12 @@ CRATE: Units: e1,e1,e4,e4,e3,e3,e3 ValidRaces: soviet TimeDelay: 4500 + UnitUpgradeCrateAction@invuln: + SelectionShares: 5 + Effect: invuln + Notification: ironcur9.aud + Upgrades: invulnerability + Duration: 600 RenderSprites: Palette: effect WithCrateBody: From bb44d76762d669ed093967cfe22c3a5d6b106b33 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 26 Sep 2014 17:38:17 +1200 Subject: [PATCH 06/11] Add a GrantUpgradeWarhead and initial TS EMP implementation. --- OpenRA.Mods.RA/DisableUpgrade.cs | 48 +++++++++++++++++ OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 3 +- .../Warheads/GrantUpgradeWarhead.cs | 54 +++++++++++++++++++ mods/ts/rules/defaults.yaml | 16 ++++++ mods/ts/rules/structures.yaml | 40 ++++++++++++++ mods/ts/sequences/misc.yaml | 6 ++- mods/ts/sequences/structures.yaml | 20 +++++++ mods/ts/weapons.yaml | 21 ++++++++ 8 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 OpenRA.Mods.RA/DisableUpgrade.cs create mode 100644 OpenRA.Mods.RA/Warheads/GrantUpgradeWarhead.cs diff --git a/OpenRA.Mods.RA/DisableUpgrade.cs b/OpenRA.Mods.RA/DisableUpgrade.cs new file mode 100644 index 0000000000..b500518323 --- /dev/null +++ b/OpenRA.Mods.RA/DisableUpgrade.cs @@ -0,0 +1,48 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class DisableUpgradeInfo : ITraitInfo + { + public readonly string RequiresUpgrade = "disable"; + + public object Create(ActorInitializer init) { return new DisableUpgrade(this); } + } + + public class DisableUpgrade : IUpgradable, IDisable + { + readonly DisableUpgradeInfo info; + bool enabled; + + public DisableUpgrade(DisableUpgradeInfo info) + { + this.info = info; + } + + public bool AcceptsUpgrade(string type) + { + return type == info.RequiresUpgrade; + } + + public void UpgradeAvailable(Actor self, string type, bool available) + { + if (type == info.RequiresUpgrade) + enabled = available; + } + + public bool Disabled { get { return enabled; } } + } +} diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index ca87819c27..04654f5bdb 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -565,9 +565,10 @@ - + + diff --git a/OpenRA.Mods.RA/Warheads/GrantUpgradeWarhead.cs b/OpenRA.Mods.RA/Warheads/GrantUpgradeWarhead.cs new file mode 100644 index 0000000000..9c99ef4551 --- /dev/null +++ b/OpenRA.Mods.RA/Warheads/GrantUpgradeWarhead.cs @@ -0,0 +1,54 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.Linq; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Traits; +using OpenRA.Mods.RA.Effects; + +namespace OpenRA.Mods.RA +{ + public class GrantUpgradeWarhead : Warhead + { + [Desc("The upgrades to apply.")] + public readonly string[] Upgrades = { }; + + [Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent upgrade.")] + public readonly int Duration = 0; + + public readonly WRange Range = WRange.FromCells(1); + + public override void DoImpact(Target target, Actor firedBy, IEnumerable damageModifiers) + { + var actors = target.Type == TargetType.Actor ? new [] { target.Actor } : + firedBy.World.FindActorsInCircle(target.CenterPosition, Range); + + foreach (var a in actors) + { + var um = a.TraitOrDefault(); + if (um == null) + return; + + foreach (var u in Upgrades) + { + if (!um.AcceptsUpgrade(a, u)) + continue; + + if (Duration > 0) + um.GrantTimedUpgrade(a, u, Duration); + else + um.GrantUpgrade(a, u, this); + } + } + } + } +} diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index 18d25dab0f..6b06fa2593 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -245,6 +245,14 @@ Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall UpgradeManager: + UpgradeOverlay@EMPDISABLE: + RequiresUpgrade: empdisable + Palette: disabled + DisableUpgrade@EMPDISABLE: + RequiresUpgrade: empdisable + TimedUpgradeBar@EMPDISABLE: + Upgrade: empdisable + Color: 255,255,255 ^Tank: AppearsOnRadar: @@ -305,6 +313,14 @@ Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall UpgradeManager: + UpgradeOverlay@EMPDISABLE: + RequiresUpgrade: empdisable + Palette: disabled + DisableUpgrade@EMPDISABLE: + RequiresUpgrade: empdisable + TimedUpgradeBar@EMPDISABLE: + Upgrade: empdisable + Color: 255,255,255 ^Helicopter: AppearsOnRadar: diff --git a/mods/ts/rules/structures.yaml b/mods/ts/rules/structures.yaml index 94a831c7a0..31c567107d 100644 --- a/mods/ts/rules/structures.yaml +++ b/mods/ts/rules/structures.yaml @@ -1181,6 +1181,46 @@ NAOBEL: Power: Amount: -150 +NAPULS: + Inherits: ^Building + Valued: + Cost: 1000 + Tooltip: + Name: EMP Cannon + Description: Disables vehicles. \nRequires power to operate.\n Strong vs all ground units\n Cannot target Aircraft + Buildable: + Queue: Defense + BuildPaletteOrder: 90 + Prerequisites: radar + Owner: nod,gdi + Building: + Footprint: xx xx + Dimensions: 2,2 + RequiresPower: + DisabledOverlay: + -GivesBuildableArea: + Health: + HP: 500 + Armor: + Type: Heavy + RevealsShroud: + Range: 8c0 + Turreted: + ROT: 10 + InitialFacing: 300 + AttackTurreted: + Armament: + Weapon: EMPulseCannon + AutoTarget: + RenderRangeCircle: + RenderDetectionCircle: + DetectCloaked: + Range: 5 + WithTurret: + Sequence: turret + Power: + Amount: -150 + ANYPOWER: Tooltip: Name: Power Plant diff --git a/mods/ts/sequences/misc.yaml b/mods/ts/sequences/misc.yaml index 2eb2cbfa0c..35e9eb27c7 100644 --- a/mods/ts/sequences/misc.yaml +++ b/mods/ts/sequences/misc.yaml @@ -161,7 +161,6 @@ explosion: pulse_explosion: pulsefx2 Start: 0 Length: * - Tick: 160 BlendMode: Additive small_watersplash: h2o_exp2 Start: 0 @@ -279,6 +278,11 @@ canister: Start: 0 Length: * +pulsball: + idle: + Start: 0 + Length: * + dragon: idle: Start: 0 diff --git a/mods/ts/sequences/structures.yaml b/mods/ts/sequences/structures.yaml index 494b3fec57..5229507fc0 100644 --- a/mods/ts/sequences/structures.yaml +++ b/mods/ts/sequences/structures.yaml @@ -698,6 +698,26 @@ nasam: icon: samicon Start: 0 +napuls: + idle: ntpuls + Start: 0 + ShadowStart: 3 + damaged-idle: ntpuls + Start: 1 + ShadowStart: 4 + critical-idle: ntpuls + Start: 2 + ShadowStart: 5 + turret: ntpuls_a + Start: 0 + Facings: 32 + make: ntpulsmk + Start: 0 + Length: 20 + ShadowStart: 20 + icon: pulsicon + Start: 0 + gavulc: idle: gtctwr Start: 0 diff --git a/mods/ts/weapons.yaml b/mods/ts/weapons.yaml index 5a8651db15..6234cddebe 100644 --- a/mods/ts/weapons.yaml +++ b/mods/ts/weapons.yaml @@ -1114,6 +1114,27 @@ TurretLaser: Warhead@2Smu: LeaveSmudge SmudgeType: Scorch +EMPulseCannon: + ReloadDelay: 100 + Range: 10c0 + Report: PLSECAN2.AUD + Projectile: Bullet + Speed: 425 + High: yes + Shadow: true + Angle: 62 + Image: pulsball + Warhead@2Eff: CreateEffect + Explosion: pulse_explosion +# Dummy warhead to allow targeting + Warhead@target: SpreadDamage + Spread: 0 + Damage: 0 + Warhead@emp: GrantUpgrade + Range: 3c0 + Duration: 250 + Upgrades: empdisable + TiberiumExplosion: Warhead@1Dam: SpreadDamage Spread: 9 From abba61dd8c01b18717e28abd48f3294dab500d52 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 28 Sep 2014 21:03:27 +1300 Subject: [PATCH 07/11] Replace RemoveOnConditions with KillsSelf. Upgrades offer more flexibility than prerequisites. --- .../UtilityCommands/UpgradeRules.cs | 7 ++ OpenRA.Mods.RA/KillsSelf.cs | 71 +++++++++++++++++ OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 - OpenRA.Mods.RA/RemoveOnConditions.cs | 79 ------------------- mods/d2k/rules/structures.yaml | 3 +- 5 files changed, 80 insertions(+), 81 deletions(-) create mode 100644 OpenRA.Mods.RA/KillsSelf.cs delete mode 100644 OpenRA.Mods.RA/RemoveOnConditions.cs diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 872f2a56de..db845b31c3 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -620,6 +620,13 @@ namespace OpenRA.Mods.Common.UtilityCommands if (depth == 1 && node.Key == "-IronCurtainable") node.Key = "-InvulnerabilityUpgrade@IRONCURTAIN"; + + // Replaced RemoveOnConditions with KillsSelf + if (depth == 1 && node.Key == "RemoveOnConditions") + { + node.Key = "KillsSelf"; + node.Value.Nodes.Add(new MiniYamlNode("RemoveInstead", new MiniYaml("true"))); + } } UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); diff --git a/OpenRA.Mods.RA/KillsSelf.cs b/OpenRA.Mods.RA/KillsSelf.cs new file mode 100644 index 0000000000..4c5916dae1 --- /dev/null +++ b/OpenRA.Mods.RA/KillsSelf.cs @@ -0,0 +1,71 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 System.Text; +using OpenRA.Primitives; +using OpenRA.Traits; +using OpenRA.Effects; + +namespace OpenRA.Mods.RA +{ + class KillsSelfInfo : ITraitInfo + { + [Desc("Enable only if this upgrade is enabled.")] + public readonly string RequiresUpgrade = null; + + [Desc("Remove the actor from the world (and destroy it) instead of killing it.")] + public readonly bool RemoveInstead = false; + + public object Create(ActorInitializer init) { return new KillsSelf(init.self, this); } + } + + class KillsSelf : INotifyAddedToWorld, IUpgradable + { + readonly KillsSelfInfo info; + readonly Actor self; + + public KillsSelf(Actor self, KillsSelfInfo info) + { + this.info = info; + this.self = self; + } + + public void AddedToWorld(Actor self) + { + if (info.RequiresUpgrade == null) + Kill(); + } + + public bool AcceptsUpgrade(string type) + { + return type == info.RequiresUpgrade; + } + + public void UpgradeAvailable(Actor self, string type, bool available) + { + if (type == info.RequiresUpgrade) + Kill(); + } + + void Kill() + { + if (self.IsDead()) + return; + + if (info.RemoveInstead || !self.HasTrait()) + self.Destroy(); + else + self.Kill(self); + } + } +} diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 04654f5bdb..cf8c78884a 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -295,7 +295,6 @@ - diff --git a/OpenRA.Mods.RA/RemoveOnConditions.cs b/OpenRA.Mods.RA/RemoveOnConditions.cs deleted file mode 100644 index 5094f781f6..0000000000 --- a/OpenRA.Mods.RA/RemoveOnConditions.cs +++ /dev/null @@ -1,79 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2014 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 System.Text; -using OpenRA.Primitives; -using OpenRA.Traits; -using OpenRA.Effects; - -namespace OpenRA.Mods.RA -{ - [Desc("Destroys the actor after a specified number of ticks if all conditions are met.")] - class RemoveOnConditionsInfo : ITraitInfo - { - [Desc("Prerequisites required before removal")] - public readonly string[] Prerequisites = {}; - - [Desc("Delay until it starts checking if you have the prerequisites", "0 = Removal attempted on AddedToWorld")] - public readonly int Delay = 0; - - [Desc("Should the trait kill instead of destroy?")] - public readonly bool KillInstead = false; - - public object Create(ActorInitializer init) { return new RemoveOnConditions(init.self, this); } - } - - class RemoveOnConditions : INotifyAddedToWorld, ITechTreeElement - { - readonly RemoveOnConditionsInfo info; - readonly Actor self; - - public RemoveOnConditions(Actor self, RemoveOnConditionsInfo info) - { - this.info = info; - this.self = self; - } - - public void AddedToWorld(Actor self) - { - Action act = () => - { - if (!info.Prerequisites.Any() || self.Owner.PlayerActor.Trait().HasPrerequisites(info.Prerequisites)) - Remove(); - else - self.Owner.PlayerActor.Trait().Add("remove_" + string.Join("_", info.Prerequisites.OrderBy(a => a)), info.Prerequisites, 0, this); - }; - - if (info.Delay <= 0 && (!info.Prerequisites.Any() || self.Owner.PlayerActor.Trait().HasPrerequisites(info.Prerequisites))) - Remove(); - else - self.World.AddFrameEndTask(w => w.Add(new DelayedAction(info.Delay, act))); - } - - void Remove() - { - if (!self.IsDead()) - { - if (info.KillInstead && self.HasTrait()) - self.Kill(self); - else - self.Destroy(); - } - } - - public void PrerequisitesAvailable(string key) { Remove(); } - public void PrerequisitesUnavailable(string key) { } - public void PrerequisitesItemHidden(string key) { } - public void PrerequisitesItemVisible(string key) { } - } -} diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 5f8f688d2e..d11237ff82 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -11,7 +11,8 @@ Name: Concrete Description: Provides a strong foundation that prevents\ndamage from the terrain. RenderSprites: - RemoveOnConditions: + KillsSelf: + RemoveInstead: true CONCRETEA: Inherits: ^CONCRETE From 22574e920b9d189530f4417091c41c1ea242698f Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 28 Sep 2014 21:08:06 +1300 Subject: [PATCH 08/11] Detonate demo trucks when they are iron-curtained. --- mods/ra/rules/vehicles.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mods/ra/rules/vehicles.yaml b/mods/ra/rules/vehicles.yaml index 6e4e7752c1..e59c60d555 100644 --- a/mods/ra/rules/vehicles.yaml +++ b/mods/ra/rules/vehicles.yaml @@ -652,6 +652,8 @@ DTRK: EmptyWeapon: MiniNuke DemoTruck: -InvulnerabilityUpgrade@IRONCURTAIN: + KillsSelf: + RequiresUpgrade: invulnerability Chronoshiftable: ExplodeInstead: yes From 8a014393a3a84e10c90acdae4d42b3a5a5575086 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 28 Sep 2014 21:22:50 +1300 Subject: [PATCH 09/11] Rename UnitUpgradeCrateAction to GrantUpgradeCrateAction. --- .../UtilityCommands/UpgradeRules.cs | 16 ++++++++++++++++ ...CrateAction.cs => GrantUpgradeCrateAction.cs} | 10 +++++----- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 2 +- mods/cnc/maps/gdi04a/map.yaml | 2 +- mods/cnc/maps/gdi04b/map.yaml | 2 +- mods/cnc/maps/the-hot-box/map.yaml | 2 +- mods/cnc/rules/misc.yaml | 2 +- mods/ra/rules/misc.yaml | 2 +- 8 files changed, 27 insertions(+), 11 deletions(-) rename OpenRA.Mods.RA/Crates/{UnitUpgradeCrateAction.cs => GrantUpgradeCrateAction.cs} (88%) diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index db845b31c3..69a6b4cc3f 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -627,6 +627,22 @@ namespace OpenRA.Mods.Common.UtilityCommands node.Key = "KillsSelf"; node.Value.Nodes.Add(new MiniYamlNode("RemoveInstead", new MiniYaml("true"))); } + + if (depth == 1 && node.Key.StartsWith("UnitUpgradeCrateAction")) + { + var parts = node.Key.Split('@'); + node.Key = "GrantUpgradeCrateAction"; + if (parts.Length > 1) + node.Key += "@" + parts[1]; + } + + if (depth == 1 && node.Key.StartsWith("-UnitUpgradeCrateAction")) + { + var parts = node.Key.Split('@'); + node.Key = "-GrantUpgradeCrateAction"; + if (parts.Length > 1) + node.Key += "@" + parts[1]; + } } UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); diff --git a/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs b/OpenRA.Mods.RA/Crates/GrantUpgradeCrateAction.cs similarity index 88% rename from OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs rename to OpenRA.Mods.RA/Crates/GrantUpgradeCrateAction.cs index 47228af0ea..6a9e7be7dc 100644 --- a/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/GrantUpgradeCrateAction.cs @@ -14,7 +14,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA.Crates { [Desc("Grants an upgrade to the collector.")] - public class UnitUpgradeCrateActionInfo : CrateActionInfo + public class GrantUpgradeCrateActionInfo : CrateActionInfo { [Desc("The upgrades to apply.")] public readonly string[] Upgrades = { }; @@ -28,15 +28,15 @@ namespace OpenRA.Mods.RA.Crates [Desc("The maximum number of extra collectors to grant the crate action to.", "-1 = no limit")] public readonly int MaxExtraCollectors = 4; - public override object Create(ActorInitializer init) { return new UnitUpgradeCrateAction(init.self, this); } + public override object Create(ActorInitializer init) { return new GrantUpgradeCrateAction(init.self, this); } } - public class UnitUpgradeCrateAction : CrateAction + public class GrantUpgradeCrateAction : CrateAction { readonly Actor self; - readonly UnitUpgradeCrateActionInfo info; + readonly GrantUpgradeCrateActionInfo info; - public UnitUpgradeCrateAction(Actor self, UnitUpgradeCrateActionInfo info) + public GrantUpgradeCrateAction(Actor self, GrantUpgradeCrateActionInfo info) : base(self, info) { this.self = self; diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index cf8c78884a..6161f5ef86 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -127,7 +127,6 @@ - @@ -568,6 +567,7 @@ + diff --git a/mods/cnc/maps/gdi04a/map.yaml b/mods/cnc/maps/gdi04a/map.yaml index 29f30066c1..78413c9b44 100644 --- a/mods/cnc/maps/gdi04a/map.yaml +++ b/mods/cnc/maps/gdi04a/map.yaml @@ -568,7 +568,7 @@ Rules: -GiveMcvCrateAction: -GiveCashCrateAction: -ExplodeCrateAction@fire: - -UnitUpgradeCrateAction@cloak: + -GrantUpgradeCrateAction@cloak: ScriptTriggers: Sequences: diff --git a/mods/cnc/maps/gdi04b/map.yaml b/mods/cnc/maps/gdi04b/map.yaml index 89b76c6ea6..1221868408 100644 --- a/mods/cnc/maps/gdi04b/map.yaml +++ b/mods/cnc/maps/gdi04b/map.yaml @@ -650,7 +650,7 @@ Rules: -GiveMcvCrateAction: -GiveCashCrateAction: -ExplodeCrateAction@fire: - -UnitUpgradeCrateAction@cloak: + -GrantUpgradeCrateAction@cloak: Sequences: diff --git a/mods/cnc/maps/the-hot-box/map.yaml b/mods/cnc/maps/the-hot-box/map.yaml index dc896e5f10..0953efc9e6 100644 --- a/mods/cnc/maps/the-hot-box/map.yaml +++ b/mods/cnc/maps/the-hot-box/map.yaml @@ -211,7 +211,7 @@ Rules: -GiveMcvCrateAction: -RevealMapCrateAction: -HideMapCrateAction: - -UnitUpgradeCrateAction@cloak: + -GrantUpgradeCrateAction@cloak: -ExplodeCrateAction@nuke: -ExplodeCrateAction@boom: -ExplodeCrateAction@fire: diff --git a/mods/cnc/rules/misc.yaml b/mods/cnc/rules/misc.yaml index f432decebe..decde903ac 100644 --- a/mods/cnc/rules/misc.yaml +++ b/mods/cnc/rules/misc.yaml @@ -14,7 +14,7 @@ CRATE: ExplodeCrateAction@fire: Weapon: Napalm.Crate SelectionShares: 5 - UnitUpgradeCrateAction@cloak: + GrantUpgradeCrateAction@cloak: SelectionShares: 5 Effect: cloak Upgrades: cloak diff --git a/mods/ra/rules/misc.yaml b/mods/ra/rules/misc.yaml index 2dd34bf0fe..08bbc5973b 100644 --- a/mods/ra/rules/misc.yaml +++ b/mods/ra/rules/misc.yaml @@ -147,7 +147,7 @@ CRATE: Units: e1,e1,e4,e4,e3,e3,e3 ValidRaces: soviet TimeDelay: 4500 - UnitUpgradeCrateAction@invuln: + GrantUpgradeCrateAction@invuln: SelectionShares: 5 Effect: invuln Notification: ironcur9.aud From b6d17d3034963bf7d3b52200575cfcfced41b11e Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 1 Oct 2014 21:37:32 +1300 Subject: [PATCH 10/11] Expose upgrades to map scripts. --- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 + .../Scripting/Properties/UpgradeProperties.cs | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 OpenRA.Mods.RA/Scripting/Properties/UpgradeProperties.cs diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 6161f5ef86..3d4967f001 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -568,6 +568,7 @@ + diff --git a/OpenRA.Mods.RA/Scripting/Properties/UpgradeProperties.cs b/OpenRA.Mods.RA/Scripting/Properties/UpgradeProperties.cs new file mode 100644 index 0000000000..35d1ae9fc2 --- /dev/null +++ b/OpenRA.Mods.RA/Scripting/Properties/UpgradeProperties.cs @@ -0,0 +1,50 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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 OpenRA.Scripting; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Scripting +{ + [ScriptPropertyGroup("General")] + public class UpgradeProperties : ScriptActorProperties, Requires + { + UpgradeManager um; + public UpgradeProperties(ScriptContext context, Actor self) + : base(context, self) + { + um = self.Trait(); + } + + [Desc("Grant an upgrade to this actor.")] + public void GrantUpgrade(string upgrade) + { + um.GrantUpgrade(self, upgrade, this); + } + + [Desc("Revoke an upgrade that was previously granted using GrantUpgrade.")] + public void RevokeUpgrade(string upgrade) + { + um.RevokeUpgrade(self, upgrade, this); + } + + [Desc("Grant a limited-time upgrade to this actor.")] + public void GrantTimedUpgrade(string upgrade, int duration) + { + um.GrantTimedUpgrade(self, upgrade, duration); + } + + [Desc("Check whether this actor accepts a specific upgrade.")] + public bool AcceptsUpgrade(string upgrade) + { + return um.AcceptsUpgrade(self, upgrade); + } + } +} \ No newline at end of file From fd14ebddb8272b9ca0a39eb8b79373c03d886300 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 1 Oct 2014 21:39:39 +1300 Subject: [PATCH 11/11] Remove the now-redundant ScriptInvulnerable trait. --- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 - .../Scripting/Properties/HealthProperties.cs | 18 ------------ .../Scripting/ScriptInvulnerable.cs | 28 ------------------- .../maps/desert-shellmap/desert-shellmap.lua | 4 +-- mods/ra/maps/desert-shellmap/map.yaml | 18 ++++++++---- mods/ra/maps/fort-lonestar/fort-lonestar.lua | 2 +- mods/ra/maps/fort-lonestar/map.yaml | 3 +- 7 files changed, 17 insertions(+), 57 deletions(-) delete mode 100644 OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 3d4967f001..57dba908c2 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -502,7 +502,6 @@ - diff --git a/OpenRA.Mods.RA/Scripting/Properties/HealthProperties.cs b/OpenRA.Mods.RA/Scripting/Properties/HealthProperties.cs index 445622cee2..c11867ff9e 100644 --- a/OpenRA.Mods.RA/Scripting/Properties/HealthProperties.cs +++ b/OpenRA.Mods.RA/Scripting/Properties/HealthProperties.cs @@ -33,22 +33,4 @@ namespace OpenRA.Mods.RA.Scripting [Desc("Maximum health of the actor.")] public int MaxHealth { get { return health.MaxHP; } } } - - [ScriptPropertyGroup("General")] - public class InvulnerableProperties : ScriptActorProperties, Requires - { - ScriptInvulnerable invulnerable; - public InvulnerableProperties(ScriptContext context, Actor self) - : base(context, self) - { - invulnerable = self.Trait(); - } - - [Desc("Set or query unit invulnerablility.")] - public bool Invulnerable - { - get { return invulnerable.Invulnerable; } - set { invulnerable.Invulnerable = value; } - } - } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs b/OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs deleted file mode 100644 index f2c8e5f067..0000000000 --- a/OpenRA.Mods.RA/Scripting/ScriptInvulnerable.cs +++ /dev/null @@ -1,28 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2014 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 OpenRA.GameRules; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - [Desc("Allows map scripts to make this actor invulnerable via actor.Invulnerable = true.")] - class ScriptInvulnerableInfo : TraitInfo {} - - class ScriptInvulnerable : IDamageModifier - { - public bool Invulnerable = false; - - public int GetDamageModifier(Actor attacker, DamageWarhead warhead) - { - return Invulnerable ? 0 : 100; - } - } -} diff --git a/mods/ra/maps/desert-shellmap/desert-shellmap.lua b/mods/ra/maps/desert-shellmap/desert-shellmap.lua index cc8b82f733..404ad46fc6 100644 --- a/mods/ra/maps/desert-shellmap/desert-shellmap.lua +++ b/mods/ra/maps/desert-shellmap/desert-shellmap.lua @@ -109,8 +109,8 @@ end SetupAlliedUnits = function() Utils.Do(Map.NamedActors, function(a) - if a.Owner == allies and a.HasProperty("Invulnerable") then - a.Invulnerable = true + if a.Owner == allies and a.HasProperty("AcceptsUpgrade") and a.AcceptsUpgrade("unkillable") then + a.GrantUpgrade("unkillable") a.Stance = "Defend" end end) diff --git a/mods/ra/maps/desert-shellmap/map.yaml b/mods/ra/maps/desert-shellmap/map.yaml index 9410038d01..711f967fa9 100644 --- a/mods/ra/maps/desert-shellmap/map.yaml +++ b/mods/ra/maps/desert-shellmap/map.yaml @@ -1295,19 +1295,20 @@ Rules: Health: HP: 200 ^Vehicle: - ScriptInvulnerable: GivesBounty: Percentage: 0 GainsExperience: Upgrades: + InvulnerabilityUpgrade@UNKILLABLE: + RequiresUpgrade: unkillable ^Tank: - ScriptInvulnerable: GivesBounty: Percentage: 0 GainsExperience: Upgrades: + InvulnerabilityUpgrade@UNKILLABLE: + RequiresUpgrade: unkillable ^Infantry: - ScriptInvulnerable: GivesBounty: Percentage: 0 GainsExperience: @@ -1318,20 +1319,25 @@ Rules: VolumeMultiplier: 0.1 DeathSounds@ZAPPED: VolumeMultiplier: 0.1 + InvulnerabilityUpgrade@UNKILLABLE: + RequiresUpgrade: unkillable ^Ship: - ScriptInvulnerable: GivesBounty: Percentage: 0 GainsExperience: Upgrades: + InvulnerabilityUpgrade@UNKILLABLE: + RequiresUpgrade: unkillable ^Plane: - ScriptInvulnerable: GivesBounty: Percentage: 0 + InvulnerabilityUpgrade@UNKILLABLE: + RequiresUpgrade: unkillable ^Building: - ScriptInvulnerable: GivesBounty: Percentage: 0 + InvulnerabilityUpgrade@UNKILLABLE: + RequiresUpgrade: unkillable Sequences: diff --git a/mods/ra/maps/fort-lonestar/fort-lonestar.lua b/mods/ra/maps/fort-lonestar/fort-lonestar.lua index d75e196207..a6f22481cb 100644 --- a/mods/ra/maps/fort-lonestar/fort-lonestar.lua +++ b/mods/ra/maps/fort-lonestar/fort-lonestar.lua @@ -147,7 +147,7 @@ WorldLoaded = function() Utils.Do(Snipers, function(a) if a.Owner == soviets then - a.Invulnerable = true + a.GrantUpgrade("unkillable") end end) diff --git a/mods/ra/maps/fort-lonestar/map.yaml b/mods/ra/maps/fort-lonestar/map.yaml index fdc907b7c1..d6130c546c 100644 --- a/mods/ra/maps/fort-lonestar/map.yaml +++ b/mods/ra/maps/fort-lonestar/map.yaml @@ -665,7 +665,8 @@ Rules: HP: 200 AutoTarget: InitialStance: Defend - ScriptInvulnerable: + InvulnerabilityUpgrade@UNKILLABLE: + RequiresUpgrade: unkillable SPY: Inherits: ^Infantry Buildable: