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