Merge pull request #6556 from pchote/upgrade-all-the-things

Add support for time-limited actor upgrades.
This commit is contained in:
Matthias Mailänder
2014-10-03 11:46:20 +02:00
43 changed files with 912 additions and 371 deletions

View File

@@ -575,6 +575,76 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
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<MiniYamlNode>();
overlayKeys.Add(new MiniYamlNode("RequiresUpgrade", "invulnerability"));
node.Value.Nodes.Add(new MiniYamlNode("UpgradeOverlay@IRONCURTAIN", new MiniYaml("", overlayKeys)));
var invulnKeys = new List<MiniYamlNode>();
invulnKeys.Add(new MiniYamlNode("RequiresUpgrade", "invulnerability"));
node.Value.Nodes.Add(new MiniYamlNode("InvulnerabilityUpgrade@IRONCURTAIN", new MiniYaml("", invulnKeys)));
var barKeys = new List<MiniYamlNode>();
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";
// Replaced RemoveOnConditions with KillsSelf
if (depth == 1 && node.Key == "RemoveOnConditions")
{
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);
}
}

View File

@@ -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<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> 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);

View File

@@ -14,26 +14,29 @@ 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 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);
[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;
@@ -42,16 +45,8 @@ namespace OpenRA.Mods.RA.Crates
bool AcceptsUpgrade(Actor a)
{
return a.TraitsImplementing<IUpgradable>()
.Any(up => info.Upgrades.Any(u => up.AcceptsUpgrade(u)));
}
void GrantActorUpgrades(Actor a)
{
foreach (var up in a.TraitsImplementing<IUpgradable>())
foreach (var u in info.Upgrades)
if (up.AcceptsUpgrade(u))
up.UpgradeAvailable(a, u, true);
var um = a.TraitOrDefault<UpgradeManager>();
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<UpgradeManager>();
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);
}

View File

@@ -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; } }
}
}

View File

@@ -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<IronCurtainable>();
}
public void Tick( World world )
{
if (a.IsDead() || b.GetDamageModifier(null, null) > 0)
world.AddFrameEndTask(w => w.Remove(this));
}
public IEnumerable<IRenderable> 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"));
}
}
}

View File

@@ -102,10 +102,10 @@ namespace OpenRA.Mods.RA
Level++;
foreach (var up in self.TraitsImplementing<IUpgradable>())
var um = self.TraitOrDefault<UpgradeManager>();
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)));

View File

@@ -17,7 +17,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class GlobalUpgradableInfo : ITraitInfo
public class GlobalUpgradableInfo : ITraitInfo, Requires<UpgradeManagerInfo>
{
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<GlobalUpgradeManager>();
globalManager = self.Owner.PlayerActor.Trait<GlobalUpgradeManager>();
manager = self.Trait<UpgradeManager>();
}
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<IUpgradable>();
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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<IronCurtainable> { }
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; }
}
}

View File

@@ -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<Health>())
self.Destroy();
else
self.Kill(self);
}
}
}

View File

@@ -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<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> 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;
}
}
}

View File

@@ -127,7 +127,6 @@
<Compile Include="Effects\Beacon.cs" />
<Compile Include="Player\PlaceBeacon.cs" />
<Compile Include="MenuPaletteEffect.cs" />
<Compile Include="Crates\UnitUpgradeCrateAction.cs" />
<Compile Include="EjectOnDeath.cs" />
<Compile Include="Air\FallsToEarth.cs" />
<Compile Include="Air\Fly.cs" />
@@ -220,7 +219,6 @@
<Compile Include="Effects\GpsDot.cs" />
<Compile Include="Effects\GpsSatellite.cs" />
<Compile Include="Effects\GravityBomb.cs" />
<Compile Include="Effects\InvulnEffect.cs" />
<Compile Include="Effects\LaserZap.cs" />
<Compile Include="Effects\Missile.cs" />
<Compile Include="Effects\NukeLaunch.cs" />
@@ -245,7 +243,6 @@
<Compile Include="Husk.cs" />
<Compile Include="Infiltration\InfiltrateForSupportPower.cs" />
<Compile Include="Invulnerable.cs" />
<Compile Include="IronCurtainable.cs" />
<Compile Include="JamsMissiles.cs" />
<Compile Include="LeavesHusk.cs" />
<Compile Include="Captures.cs" />
@@ -297,7 +294,6 @@
<Compile Include="Warheads\CreateEffectWarhead.cs" />
<Compile Include="Warheads\CreateResourceWarhead.cs" />
<Compile Include="Warheads\LeaveSmudgeWarhead.cs" />
<Compile Include="RemoveOnConditions.cs" />
<Compile Include="Widgets\Logic\TabCompletionLogic.cs" />
<Compile Include="World\RadarPings.cs" />
<Compile Include="Player\TechTree.cs" />
@@ -359,7 +355,6 @@
<Compile Include="SupportPowers\AirstrikePower.cs" />
<Compile Include="SupportPowers\ChronoshiftPower.cs" />
<Compile Include="SupportPowers\GpsPower.cs" />
<Compile Include="SupportPowers\IronCurtainPower.cs" />
<Compile Include="SupportPowers\NukePower.cs" />
<Compile Include="SupportPowers\ParatroopersPower.cs" />
<Compile Include="SupportPowers\SupportPower.cs" />
@@ -507,7 +502,6 @@
<Compile Include="Scripting\Properties\TransportProperties.cs" />
<Compile Include="Scripting\Global\CameraGlobal.cs" />
<Compile Include="Scripting\Properties\ChronosphereProperties.cs" />
<Compile Include="Scripting\ScriptInvulnerable.cs" />
<Compile Include="Console\ChatCommands.cs" />
<Compile Include="Console\DevCommands.cs" />
<Compile Include="Console\HelpCommand.cs" />
@@ -564,6 +558,16 @@
<Compile Include="Scripting\Properties\HarvesterProperties.cs" />
<Compile Include="Scripting\Properties\HelicopterProperties.cs" />
<Compile Include="Scripting\Properties\PlaneProperties.cs" />
<Compile Include="SupportPowers\GrantUpgradePower.cs" />
<Compile Include="Modifiers\UpgradeOverlay.cs" />
<Compile Include="TimedUpgradeBar.cs" />
<Compile Include="InvulnerabilityUpgrade.cs" />
<Compile Include="DisableUpgrade.cs" />
<Compile Include="UpgradeManager.cs" />
<Compile Include="KillsSelf.cs" />
<Compile Include="Warheads\GrantUpgradeWarhead.cs" />
<Compile Include="Crates\GrantUpgradeCrateAction.cs" />
<Compile Include="Scripting\Properties\UpgradeProperties.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">

View File

@@ -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<TechTree>().HasPrerequisites(info.Prerequisites))
Remove();
else
self.Owner.PlayerActor.Trait<TechTree>().Add("remove_" + string.Join("_", info.Prerequisites.OrderBy(a => a)), info.Prerequisites, 0, this);
};
if (info.Delay <= 0 && (!info.Prerequisites.Any() || self.Owner.PlayerActor.Trait<TechTree>().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<Health>())
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) { }
}
}

View File

@@ -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<ScriptInvulnerableInfo>
{
ScriptInvulnerable invulnerable;
public InvulnerableProperties(ScriptContext context, Actor self)
: base(context, self)
{
invulnerable = self.Trait<ScriptInvulnerable>();
}
[Desc("Set or query unit invulnerablility.")]
public bool Invulnerable
{
get { return invulnerable.Invulnerable; }
set { invulnerable.Invulnerable = value; }
}
}
}

View File

@@ -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<UpgradeManagerInfo>
{
UpgradeManager um;
public UpgradeProperties(ScriptContext context, Actor self)
: base(context, self)
{
um = self.Trait<UpgradeManager>();
}
[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);
}
}
}

View File

@@ -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<ScriptInvulnerable> {}
class ScriptInvulnerable : IDamageModifier
{
public bool Invulnerable = false;
public int GetDamageModifier(Actor attacker, DamageWarhead warhead)
{
return Invulnerable ? 0 : 100;
}
}
}

View File

@@ -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<RenderBuilding>().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<IronCurtainable>().Activate(target, ((IronCurtainPowerInfo)Info).Duration * 25);
foreach (var a in UnitsInRange(order.TargetLocation))
{
var um = a.TraitOrDefault<UpgradeManager>();
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<Actor> UnitsInRange(CPos xy)
{
var range = ((IronCurtainPowerInfo)Info).Range;
var range = info.Range;
var tiles = self.World.Map.FindTilesInCircle(xy, range);
var units = new List<Actor>();
foreach (var t in tiles)
units.AddRange(self.World.ActorMap.GetUnitsAt(t));
return units.Distinct().Where(a => a.HasTrait<IronCurtainable>());
return units.Distinct().Where(a =>
{
if (!a.Owner.IsAlliedWith(self.Owner))
return false;
var um = a.TraitOrDefault<UpgradeManager>();
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<IRenderable> 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";
}
}
}

View File

@@ -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<UpgradeManagerInfo>
{
[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<UpgradeManager>().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; }
}
}

View File

@@ -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<TimedUpgrade> timedUpgrades = new List<TimedUpgrade>();
readonly Dictionary<string, List<object>> sources = new Dictionary<string, List<object>>();
readonly Dictionary<string, List<Action<int, int>>> watchers = new Dictionary<string, List<Action<int, int>>>();
readonly Lazy<IEnumerable<IUpgradable>> upgradable;
public UpgradeManager(ActorInitializer init)
{
upgradable = Exts.Lazy(() => init.self.TraitsImplementing<IUpgradable>());
}
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<object> ss;
if (!sources.TryGetValue(upgrade, out ss))
{
ss = new List<object>();
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<object> 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<int, int> action)
{
if (!watchers.ContainsKey(upgrade))
watchers.Add(upgrade, new List<Action<int, int>>());
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<Action<int, int>> actions;
if (watchers.TryGetValue(u.Upgrade, out actions))
foreach (var a in actions)
a(u.Duration, u.Remaining);
}
timedUpgrades.RemoveAll(u => u.Remaining <= 0);
}
}
}

View File

@@ -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<int> 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<UpgradeManager>();
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);
}
}
}
}
}

View File

@@ -568,7 +568,7 @@ Rules:
-GiveMcvCrateAction:
-GiveCashCrateAction:
-ExplodeCrateAction@fire:
-UnitUpgradeCrateAction@cloak:
-GrantUpgradeCrateAction@cloak:
ScriptTriggers:
Sequences:

View File

@@ -650,7 +650,7 @@ Rules:
-GiveMcvCrateAction:
-GiveCashCrateAction:
-ExplodeCrateAction@fire:
-UnitUpgradeCrateAction@cloak:
-GrantUpgradeCrateAction@cloak:
Sequences:

View File

@@ -211,7 +211,7 @@ Rules:
-GiveMcvCrateAction:
-RevealMapCrateAction:
-HideMapCrateAction:
-UnitUpgradeCrateAction@cloak:
-GrantUpgradeCrateAction@cloak:
-ExplodeCrateAction@nuke:
-ExplodeCrateAction@boom:
-ExplodeCrateAction@fire:

View File

@@ -19,7 +19,6 @@
Chronoshiftable:
Passenger:
CargoType: Vehicle
IronCurtainable:
HiddenUnderFog:
GainsExperience:
GivesExperience:
@@ -48,6 +47,7 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
^Tank:
AppearsOnRadar:
@@ -70,7 +70,6 @@
Chronoshiftable:
Passenger:
CargoType: Vehicle
IronCurtainable:
HiddenUnderFog:
GainsExperience:
GivesExperience:
@@ -102,6 +101,7 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
^Helicopter:
AppearsOnRadar:
@@ -140,6 +140,7 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
^Infantry:
AppearsOnRadar:
@@ -220,6 +221,7 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
^CivInfantry:
Inherits: ^Infantry
@@ -326,6 +328,7 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
^Ship:
AppearsOnRadar:
@@ -359,6 +362,7 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
^Building:
AppearsOnRadar:

View File

@@ -14,7 +14,7 @@ CRATE:
ExplodeCrateAction@fire:
Weapon: Napalm.Crate
SelectionShares: 5
UnitUpgradeCrateAction@cloak:
GrantUpgradeCrateAction@cloak:
SelectionShares: 5
Effect: cloak
Upgrades: cloak

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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)

View File

@@ -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:

View File

@@ -147,7 +147,7 @@ WorldLoaded = function()
Utils.Do(Snipers, function(a)
if a.Owner == soviets then
a.Invulnerable = true
a.GrantUpgrade("unkillable")
end
end)

View File

@@ -665,7 +665,8 @@ Rules:
HP: 200
AutoTarget:
InitialStance: Defend
ScriptInvulnerable:
InvulnerabilityUpgrade@UNKILLABLE:
RequiresUpgrade: unkillable
SPY:
Inherits: ^Infantry
Buildable:

View File

@@ -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:

View File

@@ -20,7 +20,6 @@
Chronoshiftable:
Passenger:
CargoType: Vehicle
IronCurtainable:
AttackMove:
HiddenUnderFog:
GainsExperience:
@@ -60,6 +59,13 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
UpgradeOverlay@IRONCURTAIN:
RequiresUpgrade: invulnerability
InvulnerabilityUpgrade@IRONCURTAIN:
RequiresUpgrade: invulnerability
TimedUpgradeBar:
Upgrade: invulnerability
^Tank:
AppearsOnRadar:
@@ -83,7 +89,6 @@
Chronoshiftable:
Passenger:
CargoType: Vehicle
IronCurtainable:
AttackMove:
HiddenUnderFog:
GainsExperience:
@@ -123,6 +128,13 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
UpgradeOverlay@IRONCURTAIN:
RequiresUpgrade: invulnerability
InvulnerabilityUpgrade@IRONCURTAIN:
RequiresUpgrade: invulnerability
TimedUpgradeBar:
Upgrade: invulnerability
^Infantry:
AppearsOnRadar:
@@ -207,6 +219,7 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
^Ship:
AppearsOnRadar:
@@ -247,6 +260,13 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
UpgradeOverlay@IRONCURTAIN:
RequiresUpgrade: invulnerability
InvulnerabilityUpgrade@IRONCURTAIN:
RequiresUpgrade: invulnerability
TimedUpgradeBar:
Upgrade: invulnerability
^Plane:
AppearsOnRadar:
@@ -290,6 +310,13 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresUpgrade: selfheal
UpgradeManager:
UpgradeOverlay@IRONCURTAIN:
RequiresUpgrade: invulnerability
InvulnerabilityUpgrade@IRONCURTAIN:
RequiresUpgrade: invulnerability
TimedUpgradeBar:
Upgrade: invulnerability
^Helicopter:
Inherits: ^Plane
@@ -345,7 +372,14 @@
LuaScriptEvents:
Demolishable:
ScriptTriggers:
UpgradeManager:
UpgradeOverlay@IRONCURTAIN:
RequiresUpgrade: invulnerability
InvulnerabilityUpgrade@IRONCURTAIN:
RequiresUpgrade: invulnerability
TimedUpgradeBar:
Upgrade: invulnerability
^Defense:
Inherits: ^Building
TargetableBuilding:

View File

@@ -147,6 +147,12 @@ CRATE:
Units: e1,e1,e4,e4,e3,e3,e3
ValidRaces: soviet
TimeDelay: 4500
GrantUpgradeCrateAction@invuln:
SelectionShares: 5
Effect: invuln
Notification: ironcur9.aud
Upgrades: invulnerability
Duration: 600
RenderSprites:
Palette: effect
WithCrateBody:

View File

@@ -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

View File

@@ -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,18 +213,18 @@ IRON:
Range: 10c0
Bib:
HasMinibib: Yes
IronCurtainable:
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
@@ -260,7 +256,6 @@ PDOX:
Range: 10c0
Bib:
HasMinibib: Yes
IronCurtainable:
ChronoshiftPower:
Icon: chrono
ChargeTime: 120
@@ -314,7 +309,6 @@ TSLA:
MaxCharges: 3
ReloadTime: 120
AutoTarget:
IronCurtainable:
-RenderBuilding:
RenderRangeCircle:
-AcceptsSupplies:
@@ -361,7 +355,6 @@ AGUN:
AttackTurreted:
WithMuzzleFlash:
AutoTarget:
IronCurtainable:
-RenderBuilding:
RenderRangeCircle:
RangeCircleType: aa
@@ -399,7 +392,6 @@ DOME:
Range: 10c0
Bib:
ProvidesRadar:
IronCurtainable:
InfiltrateForExploration:
DetectCloaked:
Range: 10
@@ -428,7 +420,6 @@ PBOX:
Range: 6c0
Bib:
HasMinibib: Yes
IronCurtainable:
-AcceptsSupplies:
Turreted:
ROT: 255
@@ -476,7 +467,6 @@ HBOX:
Cloak:
InitialDelay: 125
CloakDelay: 60
IronCurtainable:
-AcceptsSupplies:
Turreted:
ROT: 255
@@ -534,7 +524,6 @@ GUN:
AttackTurreted:
WithMuzzleFlash:
AutoTarget:
IronCurtainable:
-RenderBuilding:
RenderRangeCircle:
-AcceptsSupplies:
@@ -575,7 +564,6 @@ FTUR:
BodyOrientation:
QuantizedFacings: 8
AutoTarget:
IronCurtainable:
RenderRangeCircle:
-AcceptsSupplies:
DrawLineToTarget:
@@ -620,7 +608,6 @@ SAM:
AttackTurreted:
WithMuzzleFlash:
AutoTarget:
IronCurtainable:
-RenderBuilding:
RenderRangeCircle:
RangeCircleType: aa
@@ -654,7 +641,6 @@ ATEK:
RevealsShroud:
Range: 10c0
Bib:
IronCurtainable:
GpsPower:
Icon: gps
OneShot: yes
@@ -712,7 +698,6 @@ WEAP:
RequiresPrerequisites: structures.soviet
Prerequisite: vehicles.soviet
PrimaryBuilding:
IronCurtainable:
ProductionBar:
Power:
Amount: -30
@@ -741,7 +726,6 @@ FACT:
Bib:
Production:
Produces: Building,Defense
IronCurtainable:
Valued:
Cost: 2500
Tooltip:
@@ -793,7 +777,6 @@ PROC:
StoresResources:
PipCount: 17
Capacity: 2000
IronCurtainable:
DrawLineToTarget:
CustomSellValue:
Value: 600
@@ -837,7 +820,6 @@ SILO:
StoresResources:
PipCount: 5
Capacity: 1500
IronCurtainable:
-RenderBuilding:
-EmitInfantryOnSell:
Power:
@@ -872,7 +854,6 @@ HPAD:
Production:
Produces: Aircraft, Helicopter
Reservable:
IronCurtainable:
ProductionBar:
PrimaryBuilding:
Power:
@@ -907,7 +888,6 @@ AFLD:
Production:
Produces: Aircraft, Plane
Reservable:
IronCurtainable:
AirstrikePower:
Icon: spyplane
ChargeTime: 180
@@ -962,7 +942,6 @@ POWR:
RevealsShroud:
Range: 4c0
Bib:
IronCurtainable:
DeadBuildingState:
Power:
Amount: 100
@@ -996,7 +975,6 @@ APWR:
RevealsShroud:
Range: 4c0
Bib:
IronCurtainable:
DeadBuildingState:
Power:
Amount: 200
@@ -1030,7 +1008,6 @@ STEK:
RevealsShroud:
Range: 4c0
Bib:
IronCurtainable:
Power:
Amount: -100
@@ -1065,7 +1042,6 @@ BARR:
Production:
Produces: Infantry, Soldier
PrimaryBuilding:
IronCurtainable:
ProductionBar:
ProvidesCustomPrerequisite:
Prerequisite: barracks
@@ -1101,7 +1077,6 @@ KENN:
Production:
Produces: Infantry, Dog
PrimaryBuilding:
IronCurtainable:
ProductionBar:
-EmitInfantryOnSell:
Power:
@@ -1138,7 +1113,6 @@ TENT:
Production:
Produces: Infantry, Soldier
PrimaryBuilding:
IronCurtainable:
ProductionBar:
ProvidesCustomPrerequisite:
Prerequisite: barracks
@@ -1169,7 +1143,6 @@ FIX:
HasMinibib: Yes
Reservable:
RallyPoint:
IronCurtainable:
RepairsUnits:
Interval: 10
WithRepairAnimation:
@@ -1200,7 +1173,6 @@ FACF:
RenderBuilding:
Image: FACT
Fake:
IronCurtainable:
-EmitInfantryOnSell:
Power:
Amount: -2
@@ -1231,7 +1203,6 @@ WEAF:
RenderBuildingWarFactory:
Image: WEAP
Fake:
IronCurtainable:
-EmitInfantryOnSell:
Power:
Amount: -2

View File

@@ -652,7 +652,9 @@ DTRK:
Weapon: MiniNuke
EmptyWeapon: MiniNuke
DemoTruck:
-IronCurtainable:
-InvulnerabilityUpgrade@IRONCURTAIN:
KillsSelf:
RequiresUpgrade: invulnerability
Chronoshiftable:
ExplodeInstead: yes

View File

@@ -157,6 +157,7 @@
DeathSounds@ZAPPED:
DeathSound: Zapped
DeathTypes: 6
UpgradeManager:
^CivilianInfantry:
Inherits: ^Infantry
@@ -243,6 +244,15 @@
Explodes:
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:
@@ -302,6 +312,15 @@
Explodes:
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:
@@ -348,6 +367,7 @@
ScriptTriggers:
Guard:
Guardable:
UpgradeManager:
^BlossomTree:
Tooltip:

View File

@@ -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
@@ -1183,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

View File

@@ -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

View File

@@ -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

View File

@@ -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