diff --git a/OpenRA.Mods.RA/Crate.cs b/OpenRA.Mods.RA/Crate.cs index 47108a6776..e167aa4d4c 100644 --- a/OpenRA.Mods.RA/Crate.cs +++ b/OpenRA.Mods.RA/Crate.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Render; using OpenRA.Primitives; using OpenRA.Traits; @@ -53,10 +54,12 @@ namespace OpenRA.Mods.RA public void OnCrush(Actor crusher) { - if (collected) return; + if (collected) + return; + + var shares = self.TraitsImplementing() + .Select(a => Pair.New(a, a.GetSelectionSharesOuter(crusher))); - var shares = self.TraitsImplementing().Select( - a => Pair.New(a, a.GetSelectionSharesOuter(crusher))); var totalShares = shares.Sum(a => a.Second); var n = self.World.SharedRandom.Next(totalShares); @@ -64,6 +67,7 @@ namespace OpenRA.Mods.RA collected = true; foreach (var s in shares) + { if (n < s.Second) { s.First.Activate(crusher); @@ -71,15 +75,34 @@ namespace OpenRA.Mods.RA } else n -= s.Second; + } } public void OnLanded() { + // Check whether the crate landed on anything var landedOn = self.World.ActorMap.GetUnitsAt(self.Location) - .FirstOrDefault(a => a != self); + .Where(a => a != self); - if (landedOn != null) - OnCrush(landedOn); + if (!landedOn.Any()) + return; + + var collector = landedOn.FirstOrDefault(a => + { + // Mobile is (currently) the only trait that supports crushing + var mi = a.Info.Traits.GetOrDefault(); + if (mi == null) + return false; + + // Make sure that the actor can collect this crate type + return CrushableBy(mi.Crushes, a.Owner); + }); + + // Destroy the crate if none of the units in the cell are valid collectors + if (collector != null) + OnCrush(collector); + else + self.Destroy(); } public void Tick(Actor self) diff --git a/OpenRA.Mods.RA/CrateAction.cs b/OpenRA.Mods.RA/CrateAction.cs index d0a478b791..5afda58ed1 100644 --- a/OpenRA.Mods.RA/CrateAction.cs +++ b/OpenRA.Mods.RA/CrateAction.cs @@ -42,8 +42,8 @@ namespace OpenRA.Mods.RA public class CrateAction { - public Actor self; - public CrateActionInfo info; + readonly Actor self; + readonly CrateActionInfo info; public CrateAction(Actor self, CrateActionInfo info) { @@ -75,8 +75,7 @@ namespace OpenRA.Mods.RA Sound.PlayToPlayer(collector.Owner, info.Notification); if (info.Effect != null) - collector.World.AddFrameEndTask( - w => w.Add(new CrateEffect(collector, info.Effect, info.Palette))); + collector.World.AddFrameEndTask(w => w.Add(new CrateEffect(collector, info.Effect, info.Palette))); } } } diff --git a/OpenRA.Mods.RA/Crates/DuplicateUnitCrateAction.cs b/OpenRA.Mods.RA/Crates/DuplicateUnitCrateAction.cs index 7e526969c1..de078920cb 100644 --- a/OpenRA.Mods.RA/Crates/DuplicateUnitCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/DuplicateUnitCrateAction.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; using OpenRA.Mods.RA.Move; @@ -22,14 +23,17 @@ namespace OpenRA.Mods.RA.Crates [Desc("The maximum number of duplicates to make.")] public readonly int MaxAmount = 2; - [Desc("The minimum number of duplicates to make.","Overrules MaxDuplicatesWorth.")] + [Desc("The minimum number of duplicates to make. Overrules MaxDuplicatesWorth.")] public readonly int MinAmount = 1; - [Desc("The maximum total cost allowed for the duplicates.","Duplication stops if the total worth will exceed this number.","-1 = no limit")] - public readonly int MaxDuplicatesWorth = -1; + [Desc("The maximum total value allowed for the duplicates.", "Duplication stops if the total worth will exceed this number.", "-1 = no limit")] + public readonly int MaxDuplicateValue = -1; - [Desc("The list of unit types we are allowed to duplicate.")] - public readonly string[] ValidDuplicateTypes = { "Ground", "Water" }; + [Desc("The maximum radius (in cells) that duplicates can be spawned.")] + public readonly int MaxRadius = 4; + + [Desc("The list of unit target types we are allowed to duplicate.")] + public readonly string[] ValidTargets = { "Ground", "Water" }; [Desc("Which races this crate action can occur for.")] public readonly string[] ValidRaces = { }; @@ -42,80 +46,67 @@ namespace OpenRA.Mods.RA.Crates class DuplicateUnitCrateAction : CrateAction { - public readonly DuplicateUnitCrateActionInfo Info; - readonly List usedCells = new List(); + readonly DuplicateUnitCrateActionInfo info; public DuplicateUnitCrateAction(Actor self, DuplicateUnitCrateActionInfo info) - : base(self, info) { Info = info; } + : base(self, info) + { + this.info = info; + } public bool CanGiveTo(Actor collector) { - if (Info.ValidRaces.Any() && !Info.ValidRaces.Contains(collector.Owner.Country.Race)) + if (info.ValidRaces.Any() && !info.ValidRaces.Contains(collector.Owner.Country.Race)) return false; var targetable = collector.Info.Traits.GetOrDefault(); - if (targetable == null || - !Info.ValidDuplicateTypes.Intersect(targetable.GetTargetTypes()).Any()) + if (targetable == null || !info.ValidTargets.Intersect(targetable.GetTargetTypes()).Any()) return false; - if (!GetSuitableCells(collector.Location, collector.Info.Name).Any()) return false; + var positionable = collector.TraitOrDefault(); + if (positionable == null) + return false; - return true; + return collector.World.Map.FindTilesInCircle(collector.Location, info.MaxRadius) + .Any(c => positionable.CanEnterCell(c)); } public override int GetSelectionShares(Actor collector) { - if (!CanGiveTo(collector)) return 0; + if (!CanGiveTo(collector)) + return 0; + return base.GetSelectionShares(collector); } public override void Activate(Actor collector) { - int AllowedWorthLeft = Info.MaxDuplicatesWorth; - int DupesMade = 0; + var positionable = collector.Trait(); + var candidateCells = collector.World.Map.FindTilesInCircle(collector.Location, info.MaxRadius) + .Where(c => positionable.CanEnterCell(c)).Shuffle(collector.World.SharedRandom) + .ToArray(); - while ((DupesMade < Info.MaxAmount) && (AllowedWorthLeft > 0) || (DupesMade < Info.MinAmount)) + var duplicates = Math.Min(candidateCells.Length, info.MaxAmount); + + // Restrict duplicate count to a maximum value + if (info.MaxDuplicateValue > 0) { - //If the collector has a cost, and we have a max duplicate worth, then update how much dupe worth is left - var unitCost = collector.Info.Traits.Get().Cost; - AllowedWorthLeft -= (Info.MaxDuplicatesWorth > 0) ? unitCost : 0; - if ((AllowedWorthLeft < 0) && (DupesMade >= Info.MinAmount)) - break; - - DupesMade++; - - var location = ChooseEmptyCellNear(collector, collector.Info.Name); - if (location != null) - { - usedCells.Add(location.Value); - collector.World.AddFrameEndTask( - w => w.CreateActor(collector.Info.Name, new TypeDictionary - { - new LocationInit(location.Value), - new OwnerInit(Info.Owner ?? collector.Owner.InternalName) - })); - } + var vi = collector.Info.Traits.GetOrDefault(); + if (vi != null && vi.Cost > 0) + duplicates = Math.Min(duplicates, info.MaxDuplicateValue / vi.Cost); } + + for (var i = 0; i < duplicates; i++) + { + var cell = candidateCells[i]; // Avoid modified closure bug + collector.World.AddFrameEndTask(w => w.CreateActor(collector.Info.Name, new TypeDictionary + { + new LocationInit(cell), + new OwnerInit(info.Owner ?? collector.Owner.InternalName) + })); + } + base.Activate(collector); } - - IEnumerable GetSuitableCells(CPos near, string unitName) - { - var mi = self.World.Map.Rules.Actors[unitName].Traits.Get(); - - for (var i = -3; i < 4; i++) - for (var j = -3; j < 4; j++) - if (mi.CanEnterCell(self.World, self, near + new CVec(i, j))) - yield return near + new CVec(i, j); - } - - CPos? ChooseEmptyCellNear(Actor a, string unit) - { - var possibleCells = GetSuitableCells(a.Location, unit).Where(c => !usedCells.Contains(c)).ToArray(); - if (possibleCells.Length == 0) - return null; - - return possibleCells.Random(self.World.SharedRandom); - } } } diff --git a/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs b/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs index 1996d89750..7468eca2ba 100644 --- a/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs @@ -25,13 +25,19 @@ namespace OpenRA.Mods.RA class ExplodeCrateAction : CrateAction { + readonly ExplodeCrateActionInfo info; + public ExplodeCrateAction(Actor self, ExplodeCrateActionInfo info) - : base(self, info) {} + : base(self, info) + { + this.info = info; + } public override void Activate(Actor collector) { - var weapon = self.World.Map.Rules.Weapons[((ExplodeCrateActionInfo)info).Weapon.ToLowerInvariant()]; - weapon.Impact(Target.FromPos(collector.CenterPosition), self, Enumerable.Empty()); + var weapon = collector.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()]; + weapon.Impact(Target.FromPos(collector.CenterPosition), collector, Enumerable.Empty()); + base.Activate(collector); } } diff --git a/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs b/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs index 4bdf7178e6..6356660f4c 100644 --- a/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs @@ -27,19 +27,21 @@ namespace OpenRA.Mods.RA class GiveCashCrateAction : CrateAction { + readonly GiveCashCrateActionInfo info; public GiveCashCrateAction(Actor self, GiveCashCrateActionInfo info) - : base(self, info) {} + : base(self, info) + { + this.info = info; + } public override void Activate(Actor collector) { collector.World.AddFrameEndTask(w => { - var crateInfo = (GiveCashCrateActionInfo)info; - var amount = crateInfo.Amount; - collector.Owner.PlayerActor.Trait().GiveCash(amount); + collector.Owner.PlayerActor.Trait().GiveCash(info.Amount); - if (crateInfo.UseCashTick) - w.Add(new FloatingText(collector.CenterPosition, collector.Owner.Color.RGB, FloatingText.FormatCashTick(amount), 30)); + if (info.UseCashTick) + w.Add(new FloatingText(collector.CenterPosition, collector.Owner.Color.RGB, FloatingText.FormatCashTick(info.Amount), 30)); }); base.Activate(collector); diff --git a/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs b/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs index c8ac334b0b..f71fa2d28a 100644 --- a/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs @@ -12,7 +12,7 @@ using System.Linq; namespace OpenRA.Mods.RA.Crates { - [Desc("Spawns units when collected.","Adjust selection shares when player has no base.")] + [Desc("Spawns units when collected.", "Adjust selection shares when player has no base.")] class GiveMcvCrateActionInfo : GiveUnitCrateActionInfo { [Desc("The selection shares to use if the collector has no base.")] @@ -23,19 +23,23 @@ namespace OpenRA.Mods.RA.Crates class GiveMcvCrateAction : GiveUnitCrateAction { + readonly GiveMcvCrateActionInfo info; public GiveMcvCrateAction(Actor self, GiveMcvCrateActionInfo info) - : base(self, info) { } + : base(self, info) + { + this.info = info; + } public override int GetSelectionShares(Actor collector) { + // There's some other really good reason why we shouldn't give this. if (!CanGiveTo(collector)) - return 0; // there's some other really good reason why we shouldn't give this. + return 0; - var hasBase = self.World.ActorsWithTrait() + var hasBase = collector.World.ActorsWithTrait() .Any(a => a.Actor.Owner == collector.Owner); - return hasBase ? info.SelectionShares : - ((GiveMcvCrateActionInfo)info).NoBaseSelectionShares; + return hasBase ? info.SelectionShares : info.NoBaseSelectionShares; } } } diff --git a/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs b/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs index 360060f8a6..044d41c652 100644 --- a/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs @@ -34,26 +34,29 @@ namespace OpenRA.Mods.RA.Crates class GiveUnitCrateAction : CrateAction { - public readonly GiveUnitCrateActionInfo Info; + readonly Actor self; + readonly GiveUnitCrateActionInfo info; readonly List usedCells = new List(); public GiveUnitCrateAction(Actor self, GiveUnitCrateActionInfo info) : base(self, info) { - Info = info; - if (!Info.Units.Any()) + this.self = self; + this.info = info; + if (!info.Units.Any()) throw new YamlException("A GiveUnitCrateAction does not specify any units to give. This might be because the yaml is referring to 'Unit' rather than 'Units'."); } public bool CanGiveTo(Actor collector) { - if (Info.ValidRaces.Any() && !Info.ValidRaces.Contains(collector.Owner.Country.Race)) + if (info.ValidRaces.Any() && !info.ValidRaces.Contains(collector.Owner.Country.Race)) return false; - foreach (string unit in Info.Units) + foreach (string unit in info.Units) { // avoid dumping tanks in the sea, and ships on dry land. - if (!GetSuitableCells(collector.Location, unit).Any()) return false; + if (!GetSuitableCells(collector.Location, unit).Any()) + return false; } return true; @@ -61,13 +64,15 @@ namespace OpenRA.Mods.RA.Crates public override int GetSelectionShares(Actor collector) { - if (!CanGiveTo(collector)) return 0; + if (!CanGiveTo(collector)) + return 0; + return base.GetSelectionShares(collector); } public override void Activate(Actor collector) { - foreach (var u in Info.Units) + foreach (var u in info.Units) { var unit = u; // avoiding access to modified closure @@ -79,10 +84,11 @@ namespace OpenRA.Mods.RA.Crates w => w.CreateActor(unit, new TypeDictionary { new LocationInit(location.Value), - new OwnerInit(Info.Owner ?? collector.Owner.InternalName) + new OwnerInit(info.Owner ?? collector.Owner.InternalName) })); } } + base.Activate(collector); } diff --git a/OpenRA.Mods.RA/Crates/HealUnitsCrateAction.cs b/OpenRA.Mods.RA/Crates/HealUnitsCrateAction.cs index ba9544ee40..930142329c 100644 --- a/OpenRA.Mods.RA/Crates/HealUnitsCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/HealUnitsCrateAction.cs @@ -26,15 +26,14 @@ namespace OpenRA.Mods.RA.Crates public override void Activate(Actor collector) { - base.Activate(collector); foreach (var unit in collector.World.Actors.Where(a => a.Owner == collector.Owner)) { var health = unit.TraitOrDefault(); if (health != null && !health.IsDead) - { health.InflictDamage(unit, unit, -(health.MaxHP - health.HP), null, true); - } } + + base.Activate(collector); } } } diff --git a/OpenRA.Mods.RA/Crates/HideMapCrateAction.cs b/OpenRA.Mods.RA/Crates/HideMapCrateAction.cs index 09b8ec2372..405e4ae514 100644 --- a/OpenRA.Mods.RA/Crates/HideMapCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/HideMapCrateAction.cs @@ -32,9 +32,10 @@ namespace OpenRA.Mods.RA public override void Activate(Actor collector) { - base.Activate(collector); if (collector.Owner == collector.World.LocalPlayer) collector.Owner.Shroud.ResetExploration(); + + base.Activate(collector); } } } diff --git a/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs b/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs index c54dcdc12d..50d03a2e74 100644 --- a/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs @@ -29,12 +29,14 @@ namespace OpenRA.Mods.RA class LevelUpCrateAction : CrateAction { - LevelUpCrateActionInfo Info; + readonly Actor self; + readonly LevelUpCrateActionInfo info; public LevelUpCrateAction(Actor self, LevelUpCrateActionInfo info) : base(self, info) { - Info = info; + this.self = self; + this.info = info; } public override int GetSelectionShares(Actor collector) @@ -45,34 +47,33 @@ namespace OpenRA.Mods.RA public override void Activate(Actor collector) { - collector.World.AddFrameEndTask(w => + var inRange = self.World.FindActorsInCircle(self.CenterPosition, info.Range).Where(a => { - var gainsExperience = collector.TraitOrDefault(); - if (gainsExperience != null) - gainsExperience.GiveLevels(((LevelUpCrateActionInfo)info).Levels); + // Don't upgrade the same unit twice + if (a == collector) + return false; + + // Only upgrade the collecting player's units + // TODO: Also apply to allied units? + if (a.Owner != collector.Owner) + return false; + + // Ignore units that can't level up + var ge = a.TraitOrDefault(); + return ge != null && ge.CanGainLevel; }); - var inRange = self.World.FindActorsInCircle(self.CenterPosition, Info.Range); - inRange = inRange.Where(a => - (a.Owner == collector.Owner) && - (a != collector) && - (a.TraitOrDefault() != null) && - (a.TraitOrDefault().CanGainLevel)); - if (inRange.Any()) - { - if (Info.MaxExtraCollectors > -1) - inRange = inRange.Take(Info.MaxExtraCollectors); + if (info.MaxExtraCollectors > -1) + inRange = inRange.Take(info.MaxExtraCollectors); - if (inRange.Any()) - foreach (Actor actor in inRange) - { - actor.World.AddFrameEndTask(w => - { - var gainsExperience = actor.TraitOrDefault(); - if (gainsExperience != null) - gainsExperience.GiveLevels(((LevelUpCrateActionInfo)info).Levels); - }); - } + foreach (var actor in inRange.Append(collector)) + { + actor.World.AddFrameEndTask(w => + { + var gainsExperience = actor.TraitOrDefault(); + if (gainsExperience != null) + gainsExperience.GiveLevels(((LevelUpCrateActionInfo)info).Levels); + }); } base.Activate(collector); diff --git a/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs b/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs index fbc7118ea4..4675215e82 100644 --- a/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs @@ -23,12 +23,17 @@ namespace OpenRA.Mods.RA class RevealMapCrateAction : CrateAction { + readonly RevealMapCrateActionInfo info; + public RevealMapCrateAction(Actor self, RevealMapCrateActionInfo info) - : base(self, info) {} + : base(self, info) + { + this.info = info; + } bool ShouldReveal(Player collectingPlayer) { - if (((RevealMapCrateActionInfo)info).IncludeAllies) + if (info.IncludeAllies) return collectingPlayer.World.LocalPlayer != null && collectingPlayer.Stances[collectingPlayer.World.LocalPlayer] == Stance.Ally; @@ -37,10 +42,10 @@ namespace OpenRA.Mods.RA public override void Activate(Actor collector) { - base.Activate(collector); - - if (ShouldReveal( collector.Owner )) + if (ShouldReveal(collector.Owner)) collector.Owner.Shroud.ExploreAll(collector.World); + + base.Activate(collector); } } } diff --git a/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs b/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs index 29190ced75..3086a2e246 100644 --- a/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs @@ -24,20 +24,23 @@ namespace OpenRA.Mods.RA.Crates class SupportPowerCrateAction : CrateAction { - SupportPowerCrateActionInfo Info; + SupportPowerCrateActionInfo info; public SupportPowerCrateAction(Actor self, SupportPowerCrateActionInfo info) - : base(self, info) { Info = info; } + : base(self, info) + { + this.info = info; + } // The free unit crate requires same race and the actor needs to be mobile. // We want neither of these properties for crate power proxies. public override void Activate(Actor collector) { - base.Activate(collector); - - collector.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary + collector.World.AddFrameEndTask(w => w.CreateActor(info.Proxy, new TypeDictionary { new OwnerInit(collector.Owner) })); + + base.Activate(collector); } } } diff --git a/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs b/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs index a8c2c8f14e..55543da2b3 100644 --- a/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/UnitUpgradeCrateAction.cs @@ -17,7 +17,7 @@ namespace OpenRA.Mods.RA.Crates public class UnitUpgradeCrateActionInfo : CrateActionInfo { [Desc("The upgrade to grant.")] - public readonly string[] Upgrades = {}; + public readonly string[] Upgrades = { }; [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); @@ -30,24 +30,26 @@ namespace OpenRA.Mods.RA.Crates public class UnitUpgradeCrateAction : CrateAction { - readonly UnitUpgradeCrateActionInfo Info; + readonly Actor self; + readonly UnitUpgradeCrateActionInfo info; public UnitUpgradeCrateAction(Actor self, UnitUpgradeCrateActionInfo info) : base(self, info) { - Info = info; + this.self = self; + this.info = info; } bool AcceptsUpgrade(Actor a) { return a.TraitsImplementing() - .Any(up => Info.Upgrades.Any(u => up.AcceptsUpgrade(u))); + .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) + foreach (var u in info.Upgrades) if (up.AcceptsUpgrade(u)) up.UpgradeAvailable(a, u, true); } @@ -61,13 +63,13 @@ namespace OpenRA.Mods.RA.Crates { collector.World.AddFrameEndTask(w => GrantActorUpgrades(collector)); - var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, Info.Range) + var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, info.Range) .Where(a => a != self && a.Owner == collector.Owner && AcceptsUpgrade(a)); if (actorsInRange.Any()) { - if (Info.MaxExtraCollectors > -1) - actorsInRange = actorsInRange.Take(Info.MaxExtraCollectors); + if (info.MaxExtraCollectors > -1) + actorsInRange = actorsInRange.Take(info.MaxExtraCollectors); collector.World.AddFrameEndTask(w => { diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs index bc2468f4c7..e5109c0c9c 100644 --- a/OpenRA.Utility/UpgradeRules.cs +++ b/OpenRA.Utility/UpgradeRules.cs @@ -517,6 +517,16 @@ namespace OpenRA.Utility } } + // DuplicateUnitCrateAction was tidied up + if (engineVersion < 20140912) + { + if (depth == 2 && node.Key == "MaxDuplicatesWorth" && parentKey == "DuplicateUnitCrateAction") + node.Key = "MaxDuplicateValue"; + + if (depth == 2 && node.Key == "ValidDuplicateTypes" && parentKey == "DuplicateUnitCrateAction") + node.Key = "ValidTargets"; + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } } diff --git a/mods/cnc/rules/misc.yaml b/mods/cnc/rules/misc.yaml index 040ca5dff0..f432decebe 100644 --- a/mods/cnc/rules/misc.yaml +++ b/mods/cnc/rules/misc.yaml @@ -22,7 +22,7 @@ CRATE: SelectionShares: 10 MaxAmount: 5 MinAmount: 1 - MaxDuplicatesWorth: 1250 + MaxDuplicateValue: 1250 GiveMcvCrateAction: SelectionShares: 0 NoBaseSelectionShares: 120 diff --git a/mods/ra/rules/misc.yaml b/mods/ra/rules/misc.yaml index 1588faf8b6..7f425f469f 100644 --- a/mods/ra/rules/misc.yaml +++ b/mods/ra/rules/misc.yaml @@ -93,7 +93,7 @@ CRATE: SelectionShares: 10 MaxAmount: 5 MinAmount: 1 - MaxDuplicatesWorth: 1500 + MaxDuplicateValue: 1500 GiveMcvCrateAction: SelectionShares: 2 NoBaseSelectionShares: 100