diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 3e6f22c4c5..f7ee60da4c 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -295,6 +295,7 @@ + @@ -473,6 +474,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/GainsExperience.cs b/OpenRA.Mods.Common/Traits/GainsExperience.cs index ed8c765eec..04a7e9b73f 100644 --- a/OpenRA.Mods.Common/Traits/GainsExperience.cs +++ b/OpenRA.Mods.Common/Traits/GainsExperience.cs @@ -18,7 +18,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This actor's experience increases when it has killed a GivesExperience actor.")] - public class GainsExperienceInfo : ITraitInfo, Requires + public class GainsExperienceInfo : ITraitInfo, Requires, Requires { [FieldLoader.LoadUsing("LoadUpgrades")] [Desc("Upgrades to grant at each level", @@ -29,6 +29,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Palette for the level up sprite.")] public readonly string LevelUpPalette = "effect"; + [Desc("Should the level-up animation be suppressed when actor is created?")] + public readonly bool SuppressLevelupAnimation = true; + public object Create(ActorInitializer init) { return new GainsExperience(init, this); } static object LoadUpgrades(MiniYaml y) @@ -56,6 +59,7 @@ namespace OpenRA.Mods.Common.Traits { readonly Actor self; readonly GainsExperienceInfo info; + readonly UpgradeManager um; readonly List> nextLevel = new List>(); @@ -77,18 +81,20 @@ namespace OpenRA.Mods.Common.Traits nextLevel.Add(Pair.New(kv.Key * cost, kv.Value)); if (init.Contains()) - GiveExperience(init.Get()); + GiveExperience(init.Get(), info.SuppressLevelupAnimation); + + um = self.Trait(); } public bool CanGainLevel { get { return Level < MaxLevel; } } - public void GiveLevels(int numLevels) + public void GiveLevels(int numLevels, bool silent = false) { var newLevel = Math.Min(Level + numLevels, MaxLevel); - GiveExperience(nextLevel[newLevel - 1].First - experience); + GiveExperience(nextLevel[newLevel - 1].First - experience, silent); } - public void GiveExperience(int amount) + public void GiveExperience(int amount, bool silent = false) { experience += amount; @@ -98,11 +104,12 @@ namespace OpenRA.Mods.Common.Traits Level++; - var um = self.TraitOrDefault(); - if (um != null) - foreach (var u in upgrades) - um.GrantUpgrade(self, u, this); + foreach (var u in upgrades) + um.GrantUpgrade(self, u, this); + } + if (!silent) + { 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.Common/Traits/ProduceableWithLevel.cs b/OpenRA.Mods.Common/Traits/ProduceableWithLevel.cs new file mode 100644 index 0000000000..31d380c97d --- /dev/null +++ b/OpenRA.Mods.Common/Traits/ProduceableWithLevel.cs @@ -0,0 +1,52 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Actors possessing this trait should define the GainsExperience trait. When the prerequisites are fulfilled, ", + "this trait grants a level-up to newly spawned actors. If additionally the actor's owning player defines the ProductionIconOverlay ", + "trait, the production queue icon renders with an overlay defined in that trait.")] + public class ProduceableWithLevelInfo : ITraitInfo, Requires + { + public readonly string[] Prerequisites = { }; + + [Desc("Number of levels to give to the actor on creation.")] + public readonly int InitialLevels = 1; + + [Desc("Should the level-up animation be suppressed when actor is created?")] + public readonly bool SuppressLevelupAnimation = true; + + public object Create(ActorInitializer init) { return new ProduceableWithLevel(init, this); } + } + + public class ProduceableWithLevel : INotifyCreated + { + readonly ProduceableWithLevelInfo info; + + public ProduceableWithLevel(ActorInitializer init, ProduceableWithLevelInfo info) + { + this.info = info; + } + + public void Created(Actor self) + { + if (!self.Owner.PlayerActor.Trait().HasPrerequisites(info.Prerequisites)) + return; + + var ge = self.Trait(); + if (!ge.CanGainLevel) + return; + + ge.GiveLevels(info.InitialLevels, info.SuppressLevelupAnimation); + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs b/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs index 2aeab13948..b6d99b6026 100644 --- a/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs +++ b/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs @@ -40,7 +40,7 @@ namespace OpenRA.Mods.Common.Traits /// Abstract base for enabling and disabling trait using upgrades. /// Requires basing *Info on UpgradableTraitInfo and using base(info) constructor. /// Note that EnabledByUpgrade is not called at creation even if this starts as enabled. - /// , + /// public abstract class UpgradableTrait : IUpgradable, IDisabledTrait, ISync where InfoType : UpgradableTraitInfo { public readonly InfoType Info; diff --git a/OpenRA.Mods.Common/Traits/VeteranProductionIconOverlay.cs b/OpenRA.Mods.Common/Traits/VeteranProductionIconOverlay.cs new file mode 100644 index 0000000000..efdb46815f --- /dev/null +++ b/OpenRA.Mods.Common/Traits/VeteranProductionIconOverlay.cs @@ -0,0 +1,151 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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.Common.Traits +{ + [Desc("Attach this to the player actor. When attached, enables all actors possessing the LevelupWhenCreated ", + "trait to have their production queue icons render with an overlay defined in this trait. ", + "The icon change occurs when LevelupWhenCreated.Prerequisites are met.")] + public class VeteranProductionIconOverlayInfo : ITraitInfo, Requires + { + [Desc("Image used for the overlay.")] + public readonly string Image = null; + + [Desc("Sequence used for the overlay (cannot be animated).")] + [SequenceReference("Image")] public readonly string Sequence = null; + + [Desc("Palette to render the sprite in. Reference the world actor's PaletteFrom* traits.")] + public readonly string Palette = "chrome"; + + [Desc("Point on the production icon's used as reference for offsetting the overlay. ", + "Possible values are any combination of Top, VCenter, Bottom and Left, HCenter, Right separated by a comma.")] + public readonly ReferencePoints ReferencePoint = ReferencePoints.Top | ReferencePoints.Left; + + [Desc("Pixel offset relative to the icon's reference point.")] + public readonly int2 Offset = int2.Zero; + + [Desc("Visual scale of the overlay.")] + public readonly float Scale = 1f; + + public object Create(ActorInitializer init) { return new VeteranProductionIconOverlay(init, this); } + } + + public class VeteranProductionIconOverlay : ITechTreeElement, IProductionIconOverlay + { + // HACK: TechTree doesn't associate Watcher.Key with the registering ITechTreeElement. + // So in a situation where multiple ITechTreeElements register Watchers with the same Key, + // and one removes its Watcher, all other ITechTreeElements' Watchers get removed too. + // This makes sure that the keys are unique with respect to the registering ITechTreeElement. + const string Prefix = "ProductionIconOverlay."; + + readonly Actor self; + readonly Sprite sprite; + readonly VeteranProductionIconOverlayInfo info; + + Dictionary overlayActive = new Dictionary(); + + public VeteranProductionIconOverlay(ActorInitializer init, VeteranProductionIconOverlayInfo info) + { + self = init.Self; + + var anim = new Animation(self.World, info.Image); + anim.Play(info.Sequence); + sprite = anim.Image; + + this.info = info; + + var ttc = self.Trait(); + + foreach (var a in self.World.Map.Rules.Actors.Values) + { + var uwc = a.Traits.GetOrDefault(); + if (uwc != null) + ttc.Add(MakeKey(a.Name), uwc.Prerequisites, 0, this); + } + } + + public Sprite Sprite() + { + return sprite; + } + + public string Palette() + { + return info.Palette; + } + + public float Scale() + { + return info.Scale; + } + + public float2 Offset(float2 iconSize) + { + float offsetX = 0, offsetY = 0; + switch (info.ReferencePoint & (ReferencePoints)3) + { + case ReferencePoints.Top: + offsetY = (-iconSize.Y + sprite.Size.Y) / 2; + break; + case ReferencePoints.VCenter: + break; + case ReferencePoints.Bottom: + offsetY = (iconSize.Y - sprite.Size.Y) / 2; + break; + } + + switch (info.ReferencePoint & (ReferencePoints)(3 << 2)) + { + case ReferencePoints.Left: + offsetX = (-iconSize.X + sprite.Size.X) / 2; + break; + case ReferencePoints.HCenter: + break; + case ReferencePoints.Right: + offsetX = (iconSize.X - sprite.Size.X) / 2; + break; + } + + return new float2(offsetX, offsetY) + info.Offset; + } + + public bool IsOverlayActive(ActorInfo ai) + { + bool isActive; + overlayActive.TryGetValue(ai, out isActive); + + return isActive; + } + + static string MakeKey(string name) + { + return Prefix + name; + } + + static string GetName(string key) + { + return key.Substring(Prefix.Length); + } + + public void PrerequisitesAvailable(string key) + { + var ai = self.World.Map.Rules.Actors[GetName(key)]; + overlayActive[ai] = true; + } + + public void PrerequisitesUnavailable(string key) { } + public void PrerequisitesItemHidden(string key) { } + public void PrerequisitesItemVisible(string key) { } + } +} diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 880ce354c6..9d2b1eeb68 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -75,6 +75,15 @@ namespace OpenRA.Mods.Common.Traits void PrerequisitesItemVisible(string key); } + public interface IProductionIconOverlay + { + Sprite Sprite(); + string Palette(); + float Scale(); + float2 Offset(float2 iconSize); + bool IsOverlayActive(ActorInfo ai); + } + public interface INotifyTransform { void BeforeTransform(Actor self); void OnTransform(Actor self); void AfterTransform(Actor toActor); } public interface IAcceptResources diff --git a/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs b/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs index e36069009d..a9fb0a2b6c 100644 --- a/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs @@ -79,6 +79,11 @@ namespace OpenRA.Mods.Common.Widgets var location = new float2(RenderBounds.Location) + new float2(queue.i * (IconWidth + IconSpacing), 0); WidgetUtils.DrawSHPCentered(icon.Image, location + 0.5f * iconSize, worldRenderer.Palette(bi.IconPalette), 0.5f); + var pio = queue.Trait.Actor.Owner.PlayerActor.TraitsImplementing().FirstOrDefault(); + if (pio != null && pio.IsOverlayActive(actor)) + WidgetUtils.DrawSHPCentered(pio.Sprite(), location + 0.5f * iconSize + pio.Offset(0.5f * iconSize), + worldRenderer.Palette(pio.Palette()), 0.5f * pio.Scale()); + var clock = clocks[queue.Trait]; clock.PlayFetchIndex("idle", () => current.TotalTime == 0 ? 0 : ((current.TotalTime - current.RemainingTime) diff --git a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs index 133890129e..73fe20090c 100644 --- a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs @@ -351,11 +351,18 @@ namespace OpenRA.Mods.Common.Widgets var buildableItems = CurrentQueue.BuildableItems(); + var pio = currentQueue.Actor.Owner.PlayerActor.TraitsImplementing().FirstOrDefault(); + var pioOffset = pio != null ? pio.Offset(IconSize) : new float2(0, 0); + // Icons foreach (var icon in icons.Values) { WidgetUtils.DrawSHPCentered(icon.Sprite, icon.Pos + iconOffset, icon.Palette); + // Draw the ProductionIconOverlay's sprite + if (pio != null && pio.IsOverlayActive(icon.Actor)) + WidgetUtils.DrawSHPCentered(pio.Sprite(), icon.Pos + iconOffset + pioOffset, worldRenderer.Palette(pio.Palette()), pio.Scale()); + // Build progress if (icon.Queued.Count > 0) { diff --git a/mods/ra/bits/cameo-chevron.pal b/mods/ra/bits/cameo-chevron.pal new file mode 100644 index 0000000000..46b5d0aba6 Binary files /dev/null and b/mods/ra/bits/cameo-chevron.pal differ diff --git a/mods/ra/bits/cameo-chevron.shp b/mods/ra/bits/cameo-chevron.shp new file mode 100644 index 0000000000..7c327dffde Binary files /dev/null and b/mods/ra/bits/cameo-chevron.shp differ diff --git a/mods/ra/rules/aircraft.yaml b/mods/ra/rules/aircraft.yaml index 9f37413e65..1f99aaeac8 100644 --- a/mods/ra/rules/aircraft.yaml +++ b/mods/ra/rules/aircraft.yaml @@ -122,6 +122,8 @@ MIG: SmokeTrailWhenDamaged: Offset: -853,0,171 Interval: 2 + ProduceableWithLevel: + Prerequisites: aircraft.upgraded YAK: Inherits: ^Plane @@ -178,6 +180,8 @@ YAK: SmokeTrailWhenDamaged: Offset: -853,0,0 Interval: 2 + ProduceableWithLevel: + Prerequisites: aircraft.upgraded TRAN: Inherits: ^Helicopter @@ -265,6 +269,8 @@ HELI: HuskActor: HELI.Husk SmokeTrailWhenDamaged: Offset: -427,0,0 + ProduceableWithLevel: + Prerequisites: aircraft.upgraded HIND: Inherits: ^Helicopter @@ -317,6 +323,8 @@ HIND: HuskActor: HIND.Husk SmokeTrailWhenDamaged: Offset: -427,0,0 + ProduceableWithLevel: + Prerequisites: aircraft.upgraded U2: Inherits: ^Plane diff --git a/mods/ra/rules/infantry.yaml b/mods/ra/rules/infantry.yaml index 41b19facf1..68ec721cb6 100644 --- a/mods/ra/rules/infantry.yaml +++ b/mods/ra/rules/infantry.yaml @@ -67,6 +67,8 @@ E1: AttackFrontal: WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded E2: Inherits: ^Soldier @@ -98,6 +100,8 @@ E2: Explodes: Weapon: UnitExplodeSmall Chance: 50 + ProduceableWithLevel: + Prerequisites: barracks.upgraded E3: Inherits: ^Soldier @@ -125,6 +129,8 @@ E3: AttackFrontal: WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded E4: Inherits: ^Soldier @@ -150,6 +156,8 @@ E4: AttackFrontal: WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded E6: Inherits: ^Soldier @@ -278,6 +286,8 @@ E7: AnnounceOnKill: Voiced: VoiceSet: TanyaVoice + ProduceableWithLevel: + Prerequisites: barracks.upgraded MEDI: Inherits: ^Soldier @@ -477,6 +487,8 @@ SHOK: AttackSequence: shoot Voiced: VoiceSet: ShokVoice + ProduceableWithLevel: + Prerequisites: barracks.upgraded SNIPER: Inherits: ^Soldier @@ -516,6 +528,8 @@ SNIPER: DetectCloaked: Range: 6 -MustBeDestroyed: + ProduceableWithLevel: + Prerequisites: barracks.upgraded Zombie: Inherits: ^Soldier diff --git a/mods/ra/rules/misc.yaml b/mods/ra/rules/misc.yaml index 5ce343917a..eb4f803953 100644 --- a/mods/ra/rules/misc.yaml +++ b/mods/ra/rules/misc.yaml @@ -362,6 +362,18 @@ powerproxy.paratroopers: DisplayBeacon: true BeaconPoster: pinficon +barracks.upgraded: + AlwaysVisible: + ProvidesPrerequisite: + +vehicles.upgraded: + AlwaysVisible: + ProvidesPrerequisite: + +aircraft.upgraded: + AlwaysVisible: + ProvidesPrerequisite: + mpspawn: AlwaysVisible: Immobile: diff --git a/mods/ra/rules/palettes.yaml b/mods/ra/rules/palettes.yaml index 70eb65a5f2..1812c3f55d 100644 --- a/mods/ra/rules/palettes.yaml +++ b/mods/ra/rules/palettes.yaml @@ -10,6 +10,10 @@ Filename: temperat.pal ShadowIndex: 3 AllowModifiers: false + PaletteFromFile@cameo-chevron: + Name: cameo-chevron + Filename: cameo-chevron.pal + AllowModifiers: false PaletteFromFile@effect: Name: effect Filename: temperat.pal diff --git a/mods/ra/rules/player.yaml b/mods/ra/rules/player.yaml index ce7607c5ee..40f4de7813 100644 --- a/mods/ra/rules/player.yaml +++ b/mods/ra/rules/player.yaml @@ -65,4 +65,9 @@ Player: Prerequisites: techlevel.infonly, techlevel.low, techlevel.medium, techlevel.unrestricted GlobalUpgradeManager: EnemyWatcher: + VeteranProductionIconOverlay: + Offset: 2, 2 + Image: cameo-chevron + Sequence: idle + Palette: cameo-chevron diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 5436180498..a66c4d19ca 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -855,6 +855,10 @@ WEAP: Power: Amount: -30 ProvidesPrerequisite@buildingname: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate + InfiltrateForSupportPower: + Proxy: vehicles.upgraded FACT: Inherits: ^Building @@ -1080,6 +1084,10 @@ HPAD: RequiresPrerequisites: structures.germany Prerequisite: aircraft.germany ProvidesPrerequisite@buildingname: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate + InfiltrateForSupportPower: + Proxy: aircraft.upgraded AFLD: Inherits: ^Building @@ -1185,6 +1193,10 @@ AFLD: Power: Amount: -20 ProvidesPrerequisite@buildingname: + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate + InfiltrateForSupportPower: + Proxy: aircraft.upgraded POWR: Inherits: ^Building @@ -1352,6 +1364,10 @@ BARR: Power: Amount: -20 ProvidesPrerequisite@buildingname: + InfiltrateForSupportPower: + Proxy: barracks.upgraded + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate KENN: Inherits: ^Building @@ -1455,6 +1471,10 @@ TENT: Power: Amount: -20 ProvidesPrerequisite@buildingname: + InfiltrateForSupportPower: + Proxy: barracks.upgraded + TargetableBuilding: + TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate FIX: Inherits: ^Building diff --git a/mods/ra/rules/vehicles.yaml b/mods/ra/rules/vehicles.yaml index e5718dd778..aa3274788a 100644 --- a/mods/ra/rules/vehicles.yaml +++ b/mods/ra/rules/vehicles.yaml @@ -29,6 +29,8 @@ V2RL: WithAttackAnimation: AimSequence: aim ReloadPrefix: empty- + ProduceableWithLevel: + Prerequisites: vehicles.upgraded 1TNK: Inherits: ^Tank @@ -67,6 +69,8 @@ V2RL: EmptyWeapon: UnitExplodeSmall LeavesHusk: HuskActor: 1TNK.Husk + ProduceableWithLevel: + Prerequisites: vehicles.upgraded 2TNK: Inherits: ^Tank @@ -107,6 +111,8 @@ V2RL: HuskActor: 2TNK.Husk SelectionDecorations: VisualBounds: 28,28 + ProduceableWithLevel: + Prerequisites: vehicles.upgraded 3TNK: Inherits: ^Tank @@ -147,6 +153,8 @@ V2RL: HuskActor: 3TNK.Husk SelectionDecorations: VisualBounds: 28,28 + ProduceableWithLevel: + Prerequisites: vehicles.upgraded 4TNK: Inherits: ^Tank @@ -201,6 +209,8 @@ V2RL: DamageCooldown: 150 SelectionDecorations: VisualBounds: 44,38,0,-4 + ProduceableWithLevel: + Prerequisites: vehicles.upgraded ARTY: Inherits: ^Tank @@ -232,6 +242,8 @@ ARTY: Weapon: UnitExplode Chance: 75 AutoTarget: + ProduceableWithLevel: + Prerequisites: vehicles.upgraded HARV: Inherits: ^Vehicle @@ -354,6 +366,8 @@ JEEP: Types: Infantry MaxWeight: 1 PipCount: 1 + ProduceableWithLevel: + Prerequisites: vehicles.upgraded APC: Inherits: ^Tank @@ -386,6 +400,8 @@ APC: Types: Infantry MaxWeight: 5 PipCount: 5 + ProduceableWithLevel: + Prerequisites: vehicles.upgraded MNLY.AP: Inherits: ^Tank @@ -569,6 +585,8 @@ TTNK: SelectionDecorations: VisualBounds: 30,30 AutoTarget: + ProduceableWithLevel: + Prerequisites: vehicles.upgraded FTRK: Inherits: ^Vehicle @@ -604,6 +622,8 @@ FTRK: AutoTarget: SelectionDecorations: VisualBounds: 28,28 + ProduceableWithLevel: + Prerequisites: vehicles.upgraded DTRK: Inherits: ^Vehicle @@ -668,6 +688,8 @@ CTNK: LocalYaw: -100 AttackFrontal: PortableChrono: + ProduceableWithLevel: + Prerequisites: vehicles.upgraded QTNK: Inherits: ^Tank @@ -737,4 +759,6 @@ STNK: DetectCloaked: Range: 6 -MustBeDestroyed: + ProduceableWithLevel: + Prerequisites: vehicles.upgraded diff --git a/mods/ra/sequences/misc.yaml b/mods/ra/sequences/misc.yaml index 9b7795b908..772b4c6349 100644 --- a/mods/ra/sequences/misc.yaml +++ b/mods/ra/sequences/misc.yaml @@ -382,6 +382,11 @@ rank: rank: Length: * +cameo-chevron: + idle: + Length: * + BlendMode: Additive + atomic: up: atomicup Length: * diff --git a/mods/ts/rules/civilian-infantry.yaml b/mods/ts/rules/civilian-infantry.yaml index 354b4fd794..2133a8a447 100644 --- a/mods/ts/rules/civilian-infantry.yaml +++ b/mods/ts/rules/civilian-infantry.yaml @@ -41,6 +41,8 @@ UMAGON: Voice: Attack WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded CHAMSPY: Inherits: ^Soldier @@ -96,6 +98,8 @@ MUTANT: Voice: Attack WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded MWMN: Inherits: ^Soldier @@ -119,6 +123,8 @@ MWMN: Voice: Attack WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded MUTANT3: Inherits: ^Soldier @@ -142,6 +148,8 @@ MUTANT3: Voice: Attack WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded TRATOS: Inherits: ^Soldier diff --git a/mods/ts/rules/civilian-structures.yaml b/mods/ts/rules/civilian-structures.yaml index 17fc480eb3..1f0946e63d 100644 --- a/mods/ts/rules/civilian-structures.yaml +++ b/mods/ts/rules/civilian-structures.yaml @@ -641,6 +641,9 @@ CAARMR: HP: 800 RenderBuilding: Palette: player + ProvidesPrerequisite: + Prerequisite: barracks.upgraded + Capturable: CABHUT: Inherits: ^CivBuilding diff --git a/mods/ts/rules/gdi-infantry.yaml b/mods/ts/rules/gdi-infantry.yaml index 9f6e144b79..e04dce58b1 100644 --- a/mods/ts/rules/gdi-infantry.yaml +++ b/mods/ts/rules/gdi-infantry.yaml @@ -21,6 +21,8 @@ E2: Voice: Attack WithInfantryBody: AttackSequence: throw + ProduceableWithLevel: + Prerequisites: barracks.upgraded MEDIC: Inherits: ^Soldier @@ -81,6 +83,8 @@ JUMPJET: WithInfantryBody: AttackSequence: shoot -TakeCover: + ProduceableWithLevel: + Prerequisites: barracks.upgraded GHOST: Inherits: ^Soldier @@ -117,4 +121,6 @@ GHOST: Voice: Attack WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded diff --git a/mods/ts/rules/nod-infantry.yaml b/mods/ts/rules/nod-infantry.yaml index 1ef3eafbb3..9eaedcfd0a 100644 --- a/mods/ts/rules/nod-infantry.yaml +++ b/mods/ts/rules/nod-infantry.yaml @@ -22,6 +22,8 @@ E3: Voice: Attack WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded CYBORG: Inherits: ^Cyborg @@ -53,6 +55,8 @@ CYBORG: Voice: Attack SelectionDecorations: VisualBounds: 16,31,0,-10 + ProduceableWithLevel: + Prerequisites: barracks.upgraded CYC2: Inherits: ^Cyborg @@ -86,6 +90,8 @@ CYC2: Voice: Attack SelectionDecorations: VisualBounds: 16,32,-1,-12 + ProduceableWithLevel: + Prerequisites: barracks.upgraded MHIJACK: Inherits: ^Soldier diff --git a/mods/ts/rules/shared-infantry.yaml b/mods/ts/rules/shared-infantry.yaml index 303fa6878d..1a3c6a7d14 100644 --- a/mods/ts/rules/shared-infantry.yaml +++ b/mods/ts/rules/shared-infantry.yaml @@ -26,6 +26,8 @@ E1: Voice: Attack WithInfantryBody: AttackSequence: shoot + ProduceableWithLevel: + Prerequisites: barracks.upgraded ENGINEER: Inherits: ^Soldier