Merge pull request #12406 from pchote/external-conditions
Upgrades overhaul part 3: Timed, external, and stacked conditions.
This commit is contained in:
@@ -307,7 +307,7 @@
|
|||||||
<Compile Include="Traits\Crates\GiveCashCrateAction.cs" />
|
<Compile Include="Traits\Crates\GiveCashCrateAction.cs" />
|
||||||
<Compile Include="Traits\Crates\GiveMcvCrateAction.cs" />
|
<Compile Include="Traits\Crates\GiveMcvCrateAction.cs" />
|
||||||
<Compile Include="Traits\Crates\GiveUnitCrateAction.cs" />
|
<Compile Include="Traits\Crates\GiveUnitCrateAction.cs" />
|
||||||
<Compile Include="Traits\Crates\GrantUpgradeCrateAction.cs" />
|
<Compile Include="Traits\Crates\GrantExternalConditionCrateAction.cs" />
|
||||||
<Compile Include="Traits\Crates\HealUnitsCrateAction.cs" />
|
<Compile Include="Traits\Crates\HealUnitsCrateAction.cs" />
|
||||||
<Compile Include="Traits\Crates\HideMapCrateAction.cs" />
|
<Compile Include="Traits\Crates\HideMapCrateAction.cs" />
|
||||||
<Compile Include="Traits\Crates\LevelUpCrateAction.cs" />
|
<Compile Include="Traits\Crates\LevelUpCrateAction.cs" />
|
||||||
@@ -417,7 +417,7 @@
|
|||||||
<Compile Include="Traits\Render\RenderVoxels.cs" />
|
<Compile Include="Traits\Render\RenderVoxels.cs" />
|
||||||
<Compile Include="Traits\Render\ProductionBar.cs" />
|
<Compile Include="Traits\Render\ProductionBar.cs" />
|
||||||
<Compile Include="Traits\Render\SupportPowerChargeBar.cs" />
|
<Compile Include="Traits\Render\SupportPowerChargeBar.cs" />
|
||||||
<Compile Include="Traits\Render\TimedUpgradeBar.cs" />
|
<Compile Include="Traits\Render\TimedConditionBar.cs" />
|
||||||
<Compile Include="Traits\Render\WithSpriteBarrel.cs" />
|
<Compile Include="Traits\Render\WithSpriteBarrel.cs" />
|
||||||
<Compile Include="Traits\Render\WithBuildingExplosion.cs" />
|
<Compile Include="Traits\Render\WithBuildingExplosion.cs" />
|
||||||
<Compile Include="Traits\Render\WithAttackAnimation.cs" />
|
<Compile Include="Traits\Render\WithAttackAnimation.cs" />
|
||||||
@@ -480,7 +480,7 @@
|
|||||||
<Compile Include="Traits\Sound\AttackSounds.cs" />
|
<Compile Include="Traits\Sound\AttackSounds.cs" />
|
||||||
<Compile Include="Traits\SupplyTruck.cs" />
|
<Compile Include="Traits\SupplyTruck.cs" />
|
||||||
<Compile Include="Traits\SupportPowers\AirstrikePower.cs" />
|
<Compile Include="Traits\SupportPowers\AirstrikePower.cs" />
|
||||||
<Compile Include="Traits\SupportPowers\GrantUpgradePower.cs" />
|
<Compile Include="Traits\SupportPowers\GrantExternalConditionPower.cs" />
|
||||||
<Compile Include="Traits\SupportPowers\NukePower.cs" />
|
<Compile Include="Traits\SupportPowers\NukePower.cs" />
|
||||||
<Compile Include="Traits\SupportPowers\SupportPower.cs" />
|
<Compile Include="Traits\SupportPowers\SupportPower.cs" />
|
||||||
<Compile Include="Traits\SupportPowers\SupportPowerManager.cs" />
|
<Compile Include="Traits\SupportPowers\SupportPowerManager.cs" />
|
||||||
@@ -564,7 +564,7 @@
|
|||||||
<Compile Include="Warheads\CreateResourceWarhead.cs" />
|
<Compile Include="Warheads\CreateResourceWarhead.cs" />
|
||||||
<Compile Include="Warheads\DamageWarhead.cs" />
|
<Compile Include="Warheads\DamageWarhead.cs" />
|
||||||
<Compile Include="Warheads\DestroyResourceWarhead.cs" />
|
<Compile Include="Warheads\DestroyResourceWarhead.cs" />
|
||||||
<Compile Include="Warheads\GrantUpgradeWarhead.cs" />
|
<Compile Include="Warheads\GrantExternalConditionWarhead.cs" />
|
||||||
<Compile Include="Warheads\HealthPercentageDamageWarhead.cs" />
|
<Compile Include="Warheads\HealthPercentageDamageWarhead.cs" />
|
||||||
<Compile Include="Warheads\LeaveSmudgeWarhead.cs" />
|
<Compile Include="Warheads\LeaveSmudgeWarhead.cs" />
|
||||||
<Compile Include="Warheads\SpreadDamageWarhead.cs" />
|
<Compile Include="Warheads\SpreadDamageWarhead.cs" />
|
||||||
@@ -775,6 +775,8 @@
|
|||||||
<Compile Include="Traits\AutoCarryall.cs" />
|
<Compile Include="Traits\AutoCarryall.cs" />
|
||||||
<Compile Include="Traits\World\CliffBackImpassabilityLayer.cs" />
|
<Compile Include="Traits\World\CliffBackImpassabilityLayer.cs" />
|
||||||
<Compile Include="Traits\Upgrades\GrantCondition.cs" />
|
<Compile Include="Traits\Upgrades\GrantCondition.cs" />
|
||||||
|
<Compile Include="Traits\Upgrades\ExternalConditions.cs" />
|
||||||
|
<Compile Include="Traits\Upgrades\StackedCondition.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
protected override void Created(Actor self)
|
protected override void Created(Actor self)
|
||||||
{
|
{
|
||||||
upgradeManager = self.Trait<UpgradeManager>();
|
upgradeManager = self.Trait<UpgradeManager>();
|
||||||
|
|
||||||
|
base.Created(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Attached(Actor self)
|
public virtual void Attached(Actor self)
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ using OpenRA.Traits;
|
|||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
[Desc("Grants an upgrade to the collector.")]
|
[Desc("Grants an upgrade to the collector.")]
|
||||||
public class GrantUpgradeCrateActionInfo : CrateActionInfo
|
public class GrantExternalConditionCrateActionInfo : CrateActionInfo
|
||||||
{
|
{
|
||||||
[UpgradeGrantedReference, FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
[Desc("The upgrades to apply.")]
|
[Desc("The condition to apply. Must be included in the target actor's ExternalConditions list.")]
|
||||||
public readonly string[] Upgrades = { };
|
public readonly string Condition = null;
|
||||||
|
|
||||||
[Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent upgrade.")]
|
[Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent upgrade.")]
|
||||||
public readonly int Duration = 0;
|
public readonly int Duration = 0;
|
||||||
@@ -30,37 +30,36 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
[Desc("The maximum number of extra collectors to grant the crate action to.", "-1 = no limit")]
|
[Desc("The maximum number of extra collectors to grant the crate action to.", "-1 = no limit")]
|
||||||
public readonly int MaxExtraCollectors = 4;
|
public readonly int MaxExtraCollectors = 4;
|
||||||
|
|
||||||
public override object Create(ActorInitializer init) { return new GrantUpgradeCrateAction(init.Self, this); }
|
public override object Create(ActorInitializer init) { return new GrantExternalConditionCrateAction(init.Self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GrantUpgradeCrateAction : CrateAction
|
public class GrantExternalConditionCrateAction : CrateAction
|
||||||
{
|
{
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
readonly GrantUpgradeCrateActionInfo info;
|
readonly GrantExternalConditionCrateActionInfo info;
|
||||||
|
|
||||||
public GrantUpgradeCrateAction(Actor self, GrantUpgradeCrateActionInfo info)
|
public GrantExternalConditionCrateAction(Actor self, GrantExternalConditionCrateActionInfo info)
|
||||||
: base(self, info)
|
: base(self, info)
|
||||||
{
|
{
|
||||||
this.self = self;
|
this.self = self;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AcceptsUpgrade(Actor a)
|
bool AcceptsCondition(Actor a)
|
||||||
{
|
{
|
||||||
var um = a.TraitOrDefault<UpgradeManager>();
|
var um = a.TraitOrDefault<UpgradeManager>();
|
||||||
return um != null && (info.Duration > 0 ?
|
return um != null && um.AcceptsExternalCondition(a, info.Condition);
|
||||||
info.Upgrades.Any(u => um.AcknowledgesUpgrade(a, u)) : info.Upgrades.Any(u => um.AcceptsUpgrade(a, u)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetSelectionShares(Actor collector)
|
public override int GetSelectionShares(Actor collector)
|
||||||
{
|
{
|
||||||
return AcceptsUpgrade(collector) ? info.SelectionShares : 0;
|
return AcceptsCondition(collector) ? info.SelectionShares : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Activate(Actor collector)
|
public override void Activate(Actor collector)
|
||||||
{
|
{
|
||||||
var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, info.Range)
|
var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, info.Range)
|
||||||
.Where(a => a != self && a != collector && a.Owner == collector.Owner && AcceptsUpgrade(a));
|
.Where(a => a != self && a != collector && a.Owner == collector.Owner && AcceptsCondition(a));
|
||||||
|
|
||||||
if (info.MaxExtraCollectors > -1)
|
if (info.MaxExtraCollectors > -1)
|
||||||
actorsInRange = actorsInRange.Take(info.MaxExtraCollectors);
|
actorsInRange = actorsInRange.Take(info.MaxExtraCollectors);
|
||||||
@@ -73,19 +72,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var um = a.TraitOrDefault<UpgradeManager>();
|
var um = a.TraitOrDefault<UpgradeManager>();
|
||||||
foreach (var u in info.Upgrades)
|
|
||||||
{
|
// Condition token is ignored because we never revoke this condition.
|
||||||
if (info.Duration > 0)
|
if (um != null)
|
||||||
{
|
um.GrantCondition(a, info.Condition, true, info.Duration);
|
||||||
if (um.AcknowledgesUpgrade(a, u))
|
|
||||||
um.GrantTimedUpgrade(a, u, info.Duration);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (um.AcceptsUpgrade(a, u))
|
|
||||||
um.GrantUpgrade(a, u, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -15,38 +15,35 @@ using OpenRA.Traits;
|
|||||||
namespace OpenRA.Mods.Common.Traits.Render
|
namespace OpenRA.Mods.Common.Traits.Render
|
||||||
{
|
{
|
||||||
[Desc("Visualizes the remaining time for an upgrade.")]
|
[Desc("Visualizes the remaining time for an upgrade.")]
|
||||||
class TimedUpgradeBarInfo : ITraitInfo, Requires<UpgradeManagerInfo>
|
class TimedConditionBarInfo : ITraitInfo, Requires<UpgradeManagerInfo>
|
||||||
{
|
{
|
||||||
[FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
[Desc("Upgrade that this bar corresponds to")]
|
[Desc("Condition that this bar corresponds to")]
|
||||||
public readonly string Upgrade = null;
|
public readonly string Condition = null;
|
||||||
|
|
||||||
public readonly Color Color = Color.Red;
|
public readonly Color Color = Color.Red;
|
||||||
|
|
||||||
public object Create(ActorInitializer init) { return new TimedUpgradeBar(init.Self, this); }
|
public object Create(ActorInitializer init) { return new TimedConditionBar(init.Self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimedUpgradeBar : ISelectionBar, INotifyCreated
|
class TimedConditionBar : ISelectionBar, IConditionTimerWatcher
|
||||||
{
|
{
|
||||||
readonly TimedUpgradeBarInfo info;
|
readonly TimedConditionBarInfo info;
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
float value;
|
float value;
|
||||||
|
|
||||||
public TimedUpgradeBar(Actor self, TimedUpgradeBarInfo info)
|
public TimedConditionBar(Actor self, TimedConditionBarInfo info)
|
||||||
{
|
{
|
||||||
this.self = self;
|
this.self = self;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Created(Actor self)
|
void IConditionTimerWatcher.Update(int duration, int remaining)
|
||||||
{
|
{
|
||||||
self.Trait<UpgradeManager>().RegisterWatcher(info.Upgrade, Update);
|
value = duration > 0 ? remaining * 1f / duration : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(int duration, int remaining)
|
string IConditionTimerWatcher.Condition { get { return info.Condition; } }
|
||||||
{
|
|
||||||
value = remaining * 1f / duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ISelectionBar.GetValue()
|
float ISelectionBar.GetValue()
|
||||||
{
|
{
|
||||||
@@ -19,31 +19,33 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
class GrantUpgradePowerInfo : SupportPowerInfo
|
class GrantExternalConditionPowerInfo : SupportPowerInfo
|
||||||
{
|
{
|
||||||
[UpgradeGrantedReference, FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
[Desc("The upgrades to apply.")]
|
[Desc("The condition to apply. Must be included in the target actor's ExternalConditions list.")]
|
||||||
public readonly string[] Upgrades = { };
|
public readonly string Condition = null;
|
||||||
|
|
||||||
[Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent upgrade.")]
|
[Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent condition.")]
|
||||||
public readonly int Duration = 0;
|
public readonly int Duration = 0;
|
||||||
|
|
||||||
[Desc("Cells - affects whole cells only")]
|
[Desc("Cells - affects whole cells only")]
|
||||||
public readonly int Range = 1;
|
public readonly int Range = 1;
|
||||||
public readonly string GrantUpgradeSound = "ironcur9.aud";
|
|
||||||
|
[Desc("Sound to instantly play at the targeted area.")]
|
||||||
|
public readonly string OnFireSound = null;
|
||||||
|
|
||||||
[SequenceReference, Desc("Sequence to play for granting actor when activated.",
|
[SequenceReference, Desc("Sequence to play for granting actor when activated.",
|
||||||
"This requires the actor to have the WithSpriteBody trait or one of its derivatives.")]
|
"This requires the actor to have the WithSpriteBody trait or one of its derivatives.")]
|
||||||
public readonly string GrantUpgradeSequence = "active";
|
public readonly string Sequence = "active";
|
||||||
|
|
||||||
public override object Create(ActorInitializer init) { return new GrantUpgradePower(init.Self, this); }
|
public override object Create(ActorInitializer init) { return new GrantExternalConditionPower(init.Self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class GrantUpgradePower : SupportPower
|
class GrantExternalConditionPower : SupportPower
|
||||||
{
|
{
|
||||||
GrantUpgradePowerInfo info;
|
readonly GrantExternalConditionPowerInfo info;
|
||||||
|
|
||||||
public GrantUpgradePower(Actor self, GrantUpgradePowerInfo info)
|
public GrantExternalConditionPower(Actor self, GrantExternalConditionPowerInfo info)
|
||||||
: base(self, info)
|
: base(self, info)
|
||||||
{
|
{
|
||||||
this.info = info;
|
this.info = info;
|
||||||
@@ -60,30 +62,18 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
base.Activate(self, order, manager);
|
base.Activate(self, order, manager);
|
||||||
|
|
||||||
var wsb = self.TraitOrDefault<WithSpriteBody>();
|
var wsb = self.TraitOrDefault<WithSpriteBody>();
|
||||||
if (wsb != null && wsb.DefaultAnimation.HasSequence(info.GrantUpgradeSequence))
|
if (wsb != null && wsb.DefaultAnimation.HasSequence(info.Sequence))
|
||||||
wsb.PlayCustomAnimation(self, info.GrantUpgradeSequence, () => wsb.CancelCustomAnimation(self));
|
wsb.PlayCustomAnimation(self, info.Sequence, () => wsb.CancelCustomAnimation(self));
|
||||||
|
|
||||||
Game.Sound.Play(info.GrantUpgradeSound, self.World.Map.CenterOfCell(order.TargetLocation));
|
Game.Sound.Play(info.OnFireSound, self.World.Map.CenterOfCell(order.TargetLocation));
|
||||||
|
|
||||||
foreach (var a in UnitsInRange(order.TargetLocation))
|
foreach (var a in UnitsInRange(order.TargetLocation))
|
||||||
{
|
{
|
||||||
var um = a.TraitOrDefault<UpgradeManager>();
|
var um = a.TraitOrDefault<UpgradeManager>();
|
||||||
if (um == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var u in info.Upgrades)
|
// Condition token is ignored because we never revoke this condition.
|
||||||
{
|
if (um != null)
|
||||||
if (info.Duration > 0)
|
um.GrantCondition(a, info.Condition, true, info.Duration);
|
||||||
{
|
|
||||||
if (um.AcknowledgesUpgrade(a, u))
|
|
||||||
um.GrantTimedUpgrade(a, u, info.Duration);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (um.AcceptsUpgrade(a, u))
|
|
||||||
um.GrantUpgrade(a, u, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,20 +91,19 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var um = a.TraitOrDefault<UpgradeManager>();
|
var um = a.TraitOrDefault<UpgradeManager>();
|
||||||
return um != null && (info.Duration > 0 ?
|
return um != null && um.AcceptsExternalCondition(a, info.Condition);
|
||||||
info.Upgrades.Any(u => um.AcknowledgesUpgrade(a, u)) : info.Upgrades.Any(u => um.AcceptsUpgrade(a, u)));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class SelectUpgradeTarget : IOrderGenerator
|
class SelectUpgradeTarget : IOrderGenerator
|
||||||
{
|
{
|
||||||
readonly GrantUpgradePower power;
|
readonly GrantExternalConditionPower power;
|
||||||
readonly int range;
|
readonly int range;
|
||||||
readonly Sprite tile;
|
readonly Sprite tile;
|
||||||
readonly SupportPowerManager manager;
|
readonly SupportPowerManager manager;
|
||||||
readonly string order;
|
readonly string order;
|
||||||
|
|
||||||
public SelectUpgradeTarget(World world, string order, SupportPowerManager manager, GrantUpgradePower power)
|
public SelectUpgradeTarget(World world, string order, SupportPowerManager manager, GrantExternalConditionPower power)
|
||||||
{
|
{
|
||||||
// Clear selection if using Left-Click Orders
|
// Clear selection if using Left-Click Orders
|
||||||
if (Game.Settings.Game.UseClassicMouseStyle)
|
if (Game.Settings.Game.UseClassicMouseStyle)
|
||||||
25
OpenRA.Mods.Common/Traits/Upgrades/ExternalConditions.cs
Normal file
25
OpenRA.Mods.Common/Traits/Upgrades/ExternalConditions.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2016 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, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Traits
|
||||||
|
{
|
||||||
|
[Desc("Lists conditions that are accepted from external sources (Lua, warheads, etc).",
|
||||||
|
"Externally granted conditions that aren't explicitly whitelisted will be silently ignored.")]
|
||||||
|
public class ExternalConditionsInfo : TraitInfo<ExternalConditions>
|
||||||
|
{
|
||||||
|
[UpgradeGrantedReference]
|
||||||
|
public readonly string[] Conditions = { };
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExternalConditions { }
|
||||||
|
}
|
||||||
32
OpenRA.Mods.Common/Traits/Upgrades/StackedCondition.cs
Normal file
32
OpenRA.Mods.Common/Traits/Upgrades/StackedCondition.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2016 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, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Traits
|
||||||
|
{
|
||||||
|
[Desc("Grant additional conditions when a specified condition has been granted multiple times.")]
|
||||||
|
public class StackedConditionInfo : TraitInfo<StackedCondition>
|
||||||
|
{
|
||||||
|
[FieldLoader.Require]
|
||||||
|
[UpgradeUsedReference]
|
||||||
|
[Desc("Condition to monitor.")]
|
||||||
|
public readonly string Condition = null;
|
||||||
|
|
||||||
|
[FieldLoader.Require]
|
||||||
|
[UpgradeGrantedReference]
|
||||||
|
[Desc("Conditions to grant when the monitored condition is granted multiple times.",
|
||||||
|
"The first entry is activated at 2x grants, second entry at 3x grants, and so on.")]
|
||||||
|
public readonly string[] StackedConditions = { };
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StackedCondition { }
|
||||||
|
}
|
||||||
@@ -17,6 +17,13 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
|
[RequireExplicitImplementation]
|
||||||
|
public interface IConditionTimerWatcher
|
||||||
|
{
|
||||||
|
string Condition { get; }
|
||||||
|
void Update(int duration, int remaining);
|
||||||
|
}
|
||||||
|
|
||||||
[Desc("Attach this to a unit to enable dynamic upgrades by warheads, experience, crates, support powers, etc.")]
|
[Desc("Attach this to a unit to enable dynamic upgrades by warheads, experience, crates, support powers, etc.")]
|
||||||
public class UpgradeManagerInfo : TraitInfo<UpgradeManager>, Requires<IConditionConsumerInfo> { }
|
public class UpgradeManagerInfo : TraitInfo<UpgradeManager>, Requires<IConditionConsumerInfo> { }
|
||||||
|
|
||||||
@@ -25,38 +32,16 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
/// <summary>Value used to represent an invalid token.</summary>
|
/// <summary>Value used to represent an invalid token.</summary>
|
||||||
public static readonly int InvalidConditionToken = -1;
|
public static readonly int InvalidConditionToken = -1;
|
||||||
|
|
||||||
class TimedCondition
|
class ConditionTimer
|
||||||
{
|
{
|
||||||
public class ConditionSource
|
public readonly int Token;
|
||||||
{
|
public readonly int Duration;
|
||||||
public readonly object Source;
|
|
||||||
public int Remaining;
|
public int Remaining;
|
||||||
|
|
||||||
public ConditionSource(int duration, object source)
|
public ConditionTimer(int token, int duration)
|
||||||
{
|
{
|
||||||
Remaining = duration;
|
Token = token;
|
||||||
Source = source;
|
Duration = Remaining = duration;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly string Condition;
|
|
||||||
public readonly int Duration;
|
|
||||||
public readonly HashSet<ConditionSource> Sources;
|
|
||||||
public int Remaining; // Equal to maximum of all Sources.Remaining
|
|
||||||
|
|
||||||
public TimedCondition(string condition, int duration, object source)
|
|
||||||
{
|
|
||||||
Condition = condition;
|
|
||||||
Duration = duration;
|
|
||||||
Remaining = duration;
|
|
||||||
Sources = new HashSet<ConditionSource> { new ConditionSource(duration, source) };
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Tick()
|
|
||||||
{
|
|
||||||
Remaining--;
|
|
||||||
foreach (var source in Sources)
|
|
||||||
source.Remaining--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,23 +54,31 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public readonly HashSet<int> Tokens = new HashSet<int>();
|
public readonly HashSet<int> Tokens = new HashSet<int>();
|
||||||
|
|
||||||
/// <summary>External callbacks that are to be executed when a timed condition changes.</summary>
|
/// <summary>External callbacks that are to be executed when a timed condition changes.</summary>
|
||||||
public readonly List<Action<int, int>> Watchers = new List<Action<int, int>>();
|
public readonly List<IConditionTimerWatcher> Watchers = new List<IConditionTimerWatcher>();
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly List<TimedCondition> timedConditions = new List<TimedCondition>();
|
|
||||||
|
|
||||||
Dictionary<string, ConditionState> state;
|
Dictionary<string, ConditionState> state;
|
||||||
|
readonly Dictionary<string, List<ConditionTimer>> timers = new Dictionary<string, List<ConditionTimer>>();
|
||||||
|
|
||||||
/// <summary>Each granted condition receives a unique token that is used when revoking.</summary>
|
/// <summary>Each granted condition receives a unique token that is used when revoking.</summary>
|
||||||
Dictionary<int, string> tokens = new Dictionary<int, string>();
|
Dictionary<int, string> tokens = new Dictionary<int, string>();
|
||||||
|
|
||||||
|
/// <summary>Set of whitelisted externally grantable conditions cached from ExternalConditions traits.</summary>
|
||||||
|
string[] externalConditions = { };
|
||||||
|
|
||||||
|
/// <summary>Set of conditions that are monitored for stacked bonuses, and the bonus conditions that they grant.</summary>
|
||||||
|
readonly Dictionary<string, string[]> stackedConditions = new Dictionary<string, string[]>();
|
||||||
|
|
||||||
|
/// <summary>Tokens granted by the stacked condition bonuses defined in stackedConditions.</summary>
|
||||||
|
readonly Dictionary<string, Stack<int>> stackedTokens = new Dictionary<string, Stack<int>>();
|
||||||
|
|
||||||
int nextToken = 1;
|
int nextToken = 1;
|
||||||
|
|
||||||
/// <summary>Temporary shim between the old and new upgrade/condition grant and revoke methods.</summary>
|
/// <summary>Temporary shim between the old and new upgrade/condition grant and revoke methods.</summary>
|
||||||
Dictionary<Pair<object, string>, int> objectTokenShim = new Dictionary<Pair<object, string>, int>();
|
readonly Dictionary<Pair<object, string>, int> objectTokenShim = new Dictionary<Pair<object, string>, int>();
|
||||||
|
|
||||||
/// <summary>Cache of condition -> enabled state for quick evaluation of boolean conditions.</summary>
|
/// <summary>Cache of condition -> enabled state for quick evaluation of boolean conditions.</summary>
|
||||||
Dictionary<string, bool> conditionCache = new Dictionary<string, bool>();
|
readonly Dictionary<string, bool> conditionCache = new Dictionary<string, bool>();
|
||||||
|
|
||||||
/// <summary>Read-only version of conditionCache that is passed to IConditionConsumers.</summary>
|
/// <summary>Read-only version of conditionCache that is passed to IConditionConsumers.</summary>
|
||||||
IReadOnlyDictionary<string, bool> readOnlyConditionCache;
|
IReadOnlyDictionary<string, bool> readOnlyConditionCache;
|
||||||
@@ -96,12 +89,19 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
readOnlyConditionCache = new ReadOnlyDictionary<string, bool>(conditionCache);
|
readOnlyConditionCache = new ReadOnlyDictionary<string, bool>(conditionCache);
|
||||||
|
|
||||||
var allConsumers = new HashSet<IConditionConsumer>();
|
var allConsumers = new HashSet<IConditionConsumer>();
|
||||||
|
var allWatchers = self.TraitsImplementing<IConditionTimerWatcher>().ToList();
|
||||||
|
|
||||||
foreach (var consumer in self.TraitsImplementing<IConditionConsumer>())
|
foreach (var consumer in self.TraitsImplementing<IConditionConsumer>())
|
||||||
{
|
{
|
||||||
allConsumers.Add(consumer);
|
allConsumers.Add(consumer);
|
||||||
foreach (var condition in consumer.Conditions)
|
foreach (var condition in consumer.Conditions)
|
||||||
{
|
{
|
||||||
state.GetOrAdd(condition).Consumers.Add(consumer);
|
var cs = state.GetOrAdd(condition);
|
||||||
|
cs.Consumers.Add(consumer);
|
||||||
|
foreach (var w in allWatchers)
|
||||||
|
if (w.Condition == condition)
|
||||||
|
cs.Watchers.Add(w);
|
||||||
|
|
||||||
conditionCache[condition] = false;
|
conditionCache[condition] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,6 +117,18 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
conditionCache[kv.Value] = conditionState.Tokens.Count > 0;
|
conditionCache[kv.Value] = conditionState.Tokens.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build external condition whitelist
|
||||||
|
externalConditions = self.Info.TraitInfos<ExternalConditionsInfo>()
|
||||||
|
.SelectMany(t => t.Conditions)
|
||||||
|
.Distinct()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var sc in self.Info.TraitInfos<StackedConditionInfo>())
|
||||||
|
{
|
||||||
|
stackedConditions[sc.Condition] = sc.StackedConditions;
|
||||||
|
stackedTokens[sc.Condition] = new Stack<int>();
|
||||||
|
}
|
||||||
|
|
||||||
// Update all traits with their initial condition state
|
// Update all traits with their initial condition state
|
||||||
foreach (var consumer in allConsumers)
|
foreach (var consumer in allConsumers)
|
||||||
consumer.ConditionsChanged(self, readOnlyConditionCache);
|
consumer.ConditionsChanged(self, readOnlyConditionCache);
|
||||||
@@ -137,15 +149,35 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
foreach (var t in conditionState.Consumers)
|
foreach (var t in conditionState.Consumers)
|
||||||
t.ConditionsChanged(self, readOnlyConditionCache);
|
t.ConditionsChanged(self, readOnlyConditionCache);
|
||||||
|
|
||||||
|
string[] sc;
|
||||||
|
if (stackedConditions.TryGetValue(condition, out sc))
|
||||||
|
{
|
||||||
|
var target = (conditionState.Tokens.Count - 1).Clamp(0, sc.Length);
|
||||||
|
var st = stackedTokens[condition];
|
||||||
|
for (var i = st.Count; i < target; i++)
|
||||||
|
st.Push(GrantCondition(self, sc[i]));
|
||||||
|
|
||||||
|
for (var i = st.Count; i > target; i--)
|
||||||
|
RevokeCondition(self, st.Pop());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Grants a specified condition.</summary>
|
/// <summary>Grants a specified condition.</summary>
|
||||||
/// <returns>The token that is used to revoke this condition.</returns>
|
/// <returns>The token that is used to revoke this condition.</returns>
|
||||||
public int GrantCondition(Actor self, string condition)
|
/// <param name="external">Validate against the external condition whitelist.</param>
|
||||||
|
/// <param name="duration">Automatically revoke condition after this delay if non-zero.</param>
|
||||||
|
public int GrantCondition(Actor self, string condition, bool external = false, int duration = 0)
|
||||||
{
|
{
|
||||||
|
if (external && !externalConditions.Contains(condition))
|
||||||
|
return InvalidConditionToken;
|
||||||
|
|
||||||
var token = nextToken++;
|
var token = nextToken++;
|
||||||
tokens.Add(token, condition);
|
tokens.Add(token, condition);
|
||||||
|
|
||||||
|
if (duration > 0)
|
||||||
|
timers.GetOrAdd(condition).Add(new ConditionTimer(token, duration));
|
||||||
|
|
||||||
// Conditions may be granted before the state is initialized.
|
// Conditions may be granted before the state is initialized.
|
||||||
// These conditions will be processed in INotifyCreated.Created.
|
// These conditions will be processed in INotifyCreated.Created.
|
||||||
if (state != null)
|
if (state != null)
|
||||||
@@ -155,7 +187,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Revokes a previously granted condition.</summary>
|
/// <summary>Revokes a previously granted condition.</summary>
|
||||||
/// <returns>The invalid token ID</returns>
|
/// <returns>The invalid token ID.</returns>
|
||||||
/// <param name="token">The token ID returned by GrantCondition.</param>
|
/// <param name="token">The token ID returned by GrantCondition.</param>
|
||||||
public int RevokeCondition(Actor self, int token)
|
public int RevokeCondition(Actor self, int token)
|
||||||
{
|
{
|
||||||
@@ -165,6 +197,15 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
tokens.Remove(token);
|
tokens.Remove(token);
|
||||||
|
|
||||||
|
// Clean up timers
|
||||||
|
List<ConditionTimer> ct;
|
||||||
|
if (timers.TryGetValue(condition, out ct))
|
||||||
|
{
|
||||||
|
ct.RemoveAll(t => t.Token == token);
|
||||||
|
if (!ct.Any())
|
||||||
|
timers.Remove(condition);
|
||||||
|
}
|
||||||
|
|
||||||
// Conditions may be granted and revoked before the state is initialized.
|
// Conditions may be granted and revoked before the state is initialized.
|
||||||
if (state != null)
|
if (state != null)
|
||||||
UpdateConditionState(self, condition, token, true);
|
UpdateConditionState(self, condition, token, true);
|
||||||
@@ -172,6 +213,61 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return InvalidConditionToken;
|
return InvalidConditionToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns true if the given external condition will have an effect on this actor.</summary>
|
||||||
|
public bool AcceptsExternalCondition(Actor self, string condition)
|
||||||
|
{
|
||||||
|
if (state == null)
|
||||||
|
throw new InvalidOperationException("AcceptsExternalCondition cannot be queried before the actor has been fully created.");
|
||||||
|
|
||||||
|
if (!externalConditions.Contains(condition))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string[] sc;
|
||||||
|
if (stackedConditions.TryGetValue(condition, out sc))
|
||||||
|
return stackedTokens[condition].Count < sc.Length;
|
||||||
|
|
||||||
|
return !conditionCache[condition];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns whether the specified token is valid for RevokeCondition</summary>
|
||||||
|
public bool TokenValid(Actor self, int token)
|
||||||
|
{
|
||||||
|
return tokens.ContainsKey(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly HashSet<int> timersToRemove = new HashSet<int>();
|
||||||
|
void ITick.Tick(Actor self)
|
||||||
|
{
|
||||||
|
// Watchers will be receiving notifications while the condition is enabled.
|
||||||
|
// They will also be provided with the number of ticks before the condition is disabled,
|
||||||
|
// as well as the duration of the longest active instance.
|
||||||
|
foreach (var kv in timers)
|
||||||
|
{
|
||||||
|
var duration = 0;
|
||||||
|
var remaining = 0;
|
||||||
|
foreach (var t in kv.Value)
|
||||||
|
{
|
||||||
|
if (--t.Remaining <= 0)
|
||||||
|
timersToRemove.Add(t.Token);
|
||||||
|
|
||||||
|
// Track the duration and remaining time for the longest remaining timer
|
||||||
|
if (t.Remaining > remaining)
|
||||||
|
{
|
||||||
|
duration = t.Duration;
|
||||||
|
remaining = t.Remaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var w in state[kv.Key].Watchers)
|
||||||
|
w.Update(duration, remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in timersToRemove)
|
||||||
|
RevokeCondition(self, t);
|
||||||
|
|
||||||
|
timersToRemove.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
#region Shim methods for legacy upgrade granting code
|
#region Shim methods for legacy upgrade granting code
|
||||||
|
|
||||||
void CheckCanManageConditions()
|
void CheckCanManageConditions()
|
||||||
@@ -180,36 +276,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
throw new InvalidOperationException("Conditions cannot be managed until the actor has been fully created.");
|
throw new InvalidOperationException("Conditions cannot be managed until the actor has been fully created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Upgrade level increments are limited to dupesAllowed per source, i.e., if a single
|
|
||||||
/// source attempts granting more upgrades than dupesAllowed, they will not accumulate. They will
|
|
||||||
/// replace each other instead, leaving only the most recently granted upgrade active. Each new
|
|
||||||
/// upgrade granting request will increment the upgrade's level until AcceptsUpgrade starts
|
|
||||||
/// returning false. Then, when no new levels are accepted, the upgrade source with the shortest
|
|
||||||
/// remaining upgrade duration will be replaced by the new source.</summary>
|
|
||||||
public void GrantTimedUpgrade(Actor self, string upgrade, int duration, object source = null, int dupesAllowed = 1)
|
public void GrantTimedUpgrade(Actor self, string upgrade, int duration, object source = null, int dupesAllowed = 1)
|
||||||
{
|
{
|
||||||
var timed = timedConditions.FirstOrDefault(u => u.Condition == upgrade);
|
CheckCanManageConditions();
|
||||||
if (timed == null)
|
var token = GrantCondition(self, upgrade, false, duration);
|
||||||
{
|
if (source != null)
|
||||||
timed = new TimedCondition(upgrade, duration, source);
|
objectTokenShim[Pair.New(source, upgrade)] = token;
|
||||||
timedConditions.Add(timed);
|
|
||||||
GrantUpgrade(self, upgrade, timed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var srcs = timed.Sources.Where(s => s.Source == source);
|
|
||||||
if (srcs.Count() < dupesAllowed)
|
|
||||||
{
|
|
||||||
timed.Sources.Add(new TimedCondition.ConditionSource(duration, source));
|
|
||||||
if (AcceptsUpgrade(self, upgrade))
|
|
||||||
GrantUpgrade(self, upgrade, timed);
|
|
||||||
else
|
|
||||||
timed.Sources.Remove(timed.Sources.MinBy(s => s.Remaining));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
srcs.MinBy(s => s.Remaining).Remaining = duration;
|
|
||||||
|
|
||||||
timed.Remaining = Math.Max(duration, timed.Remaining);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GrantUpgrade(Actor self, string upgrade, object source)
|
public void GrantUpgrade(Actor self, string upgrade, object source)
|
||||||
@@ -242,39 +314,6 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return !enabled;
|
return !enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterWatcher(string upgrade, Action<int, int> action)
|
|
||||||
{
|
|
||||||
CheckCanManageConditions();
|
|
||||||
|
|
||||||
ConditionState s;
|
|
||||||
if (!state.TryGetValue(upgrade, out s))
|
|
||||||
return;
|
|
||||||
|
|
||||||
s.Watchers.Add(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Watchers will be receiving notifications while the condition is enabled.
|
|
||||||
/// They will also be provided with the number of ticks before the condition is disabled,
|
|
||||||
/// as well as the duration in ticks of the timed upgrade (provided in the first call to
|
|
||||||
/// GrantTimedUpgrade).</summary>
|
|
||||||
void ITick.Tick(Actor self)
|
|
||||||
{
|
|
||||||
foreach (var u in timedConditions)
|
|
||||||
{
|
|
||||||
u.Tick();
|
|
||||||
foreach (var source in u.Sources)
|
|
||||||
if (source.Remaining <= 0)
|
|
||||||
RevokeUpgrade(self, u.Condition, u);
|
|
||||||
|
|
||||||
u.Sources.RemoveWhere(source => source.Remaining <= 0);
|
|
||||||
|
|
||||||
foreach (var a in state[u.Condition].Watchers)
|
|
||||||
a(u.Duration, u.Remaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
timedConditions.RemoveAll(u => u.Remaining <= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,28 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RenameNodeKey(MiniYamlNode node, string key)
|
||||||
|
{
|
||||||
|
var parts = node.Key.Split('@');
|
||||||
|
node.Key = key;
|
||||||
|
if (parts.Length > 1)
|
||||||
|
node.Key += "@" + parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertUpgradesToCondition(MiniYamlNode parent, MiniYamlNode node, string upgradesKey, string conditionKey)
|
||||||
|
{
|
||||||
|
var upgradesNode = node.Value.Nodes.FirstOrDefault(n => n.Key == upgradesKey);
|
||||||
|
if (upgradesNode != null)
|
||||||
|
{
|
||||||
|
var conditions = FieldLoader.GetValue<string[]>("", upgradesNode.Value.Value);
|
||||||
|
if (conditions.Length > 1)
|
||||||
|
Console.WriteLine("Unable to automatically migrate {0}:{1} {2} to {3}. This must be corrected manually",
|
||||||
|
parent.Key, node.Key, upgradesKey, conditionKey);
|
||||||
|
else
|
||||||
|
upgradesNode.Key = conditionKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static void UpgradeActorRules(ModData modData, int engineVersion, ref List<MiniYamlNode> nodes, MiniYamlNode parent, int depth)
|
internal static void UpgradeActorRules(ModData modData, int engineVersion, ref List<MiniYamlNode> nodes, MiniYamlNode parent, int depth)
|
||||||
{
|
{
|
||||||
var addNodes = new List<MiniYamlNode>();
|
var addNodes = new List<MiniYamlNode>();
|
||||||
@@ -118,10 +140,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
if (s != null)
|
if (s != null)
|
||||||
s.Key = "Image";
|
s.Key = "Image";
|
||||||
|
|
||||||
var parts = node.Key.Split('@');
|
RenameNodeKey(node, "WithDamageOverlay");
|
||||||
node.Key = "WithDamageOverlay";
|
|
||||||
if (parts.Length > 1)
|
|
||||||
node.Key += "@" + parts[1];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,13 +154,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
if (engineVersion < 20160611)
|
if (engineVersion < 20160611)
|
||||||
{
|
{
|
||||||
// Deprecated WithSpriteRotorOverlay
|
// Deprecated WithSpriteRotorOverlay
|
||||||
if (depth == 1 && node.Key.StartsWith("WithSpriteRotorOverlay"))
|
if (depth == 1 && node.Key.StartsWith("WithSpriteRotorOverlay", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
var parts = node.Key.Split('@');
|
RenameNodeKey(node, "WithIdleOverlay");
|
||||||
node.Key = "WithIdleOverlay";
|
|
||||||
if (parts.Length > 1)
|
|
||||||
node.Key += "@" + parts[1];
|
|
||||||
|
|
||||||
Console.WriteLine("The 'WithSpriteRotorOverlay' trait has been removed.");
|
Console.WriteLine("The 'WithSpriteRotorOverlay' trait has been removed.");
|
||||||
Console.WriteLine("Its functionality can be fully replicated with 'WithIdleOverlay' + upgrades.");
|
Console.WriteLine("Its functionality can be fully replicated with 'WithIdleOverlay' + upgrades.");
|
||||||
Console.WriteLine("Look at the helicopters in our RA / C&C1 mods for implementation details.");
|
Console.WriteLine("Look at the helicopters in our RA / C&C1 mods for implementation details.");
|
||||||
@@ -282,13 +297,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
|
|
||||||
if (engineVersion < 20160818)
|
if (engineVersion < 20160818)
|
||||||
{
|
{
|
||||||
if (depth == 1 && node.Key.StartsWith("UpgradeOnDamage"))
|
if (depth == 1 && node.Key.StartsWith("UpgradeOnDamage", StringComparison.Ordinal))
|
||||||
{
|
RenameNodeKey(node, "UpgradeOnDamageState");
|
||||||
var parts = node.Key.Split('@');
|
|
||||||
node.Key = "UpgradeOnDamageState";
|
|
||||||
if (parts.Length > 1)
|
|
||||||
node.Key += "@" + parts[1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayTimer was replaced by DisplayTimerStances
|
// DisplayTimer was replaced by DisplayTimerStances
|
||||||
@@ -435,7 +445,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename Replaced upgrade consumers with conditions
|
// Replaced upgrade consumers with conditions
|
||||||
if (engineVersion < 20161117)
|
if (engineVersion < 20161117)
|
||||||
{
|
{
|
||||||
var upgradeTypesNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "UpgradeTypes");
|
var upgradeTypesNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "UpgradeTypes");
|
||||||
@@ -480,16 +490,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
if (engineVersion < 20161119)
|
if (engineVersion < 20161119)
|
||||||
{
|
{
|
||||||
// Migrated carryalls over to new conditions system
|
// Migrated carryalls over to new conditions system
|
||||||
var carryableUpgradesNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "CarryableUpgrades");
|
ConvertUpgradesToCondition(parent, node, "CarryableUpgrades", "CarriedCondition");
|
||||||
if (carryableUpgradesNode != null)
|
|
||||||
{
|
|
||||||
var conditions = FieldLoader.GetValue<string[]>("", carryableUpgradesNode.Value.Value);
|
|
||||||
if (conditions.Length > 1)
|
|
||||||
Console.WriteLine("Unable to automatically migrate {0}:{1} CarryableUpgrades to CarriedCondition. This must be corrected manually",
|
|
||||||
parent.Key, node.Key);
|
|
||||||
else
|
|
||||||
carryableUpgradesNode.Key = "CarriedCondition";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.Key == "WithDecorationCarryable")
|
if (node.Key == "WithDecorationCarryable")
|
||||||
{
|
{
|
||||||
@@ -498,6 +499,39 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (engineVersion < 20161120)
|
||||||
|
{
|
||||||
|
if (node.Key.StartsWith("TimedUpgradeBar", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
RenameNodeKey(node, "TimedConditionBar");
|
||||||
|
ConvertUpgradesToCondition(parent, node, "Upgrade", "Condition");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.Key.StartsWith("GrantUpgradePower", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Console.WriteLine("GrantUpgradePower Condition must be manually added to all target actor's ExternalConditions list.");
|
||||||
|
RenameNodeKey(node, "GrantExternalConditionPower");
|
||||||
|
ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
|
||||||
|
|
||||||
|
var soundNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "GrantUpgradeSound");
|
||||||
|
if (soundNode != null)
|
||||||
|
soundNode.Key = "OnFireSound";
|
||||||
|
else
|
||||||
|
node.Value.Nodes.Add(new MiniYamlNode("OnFireSound", "ironcur9.aud"));
|
||||||
|
|
||||||
|
var sequenceNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "GrantUpgradeSequence");
|
||||||
|
if (sequenceNode != null)
|
||||||
|
sequenceNode.Key = "Sequence";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.Key.StartsWith("GrantUpgradeCrateAction", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Console.WriteLine("GrantUpgradeCrateAction Condition must be manually added to all target actor's ExternalConditions list.");
|
||||||
|
RenameNodeKey(node, "GrantExternalConditionCrateAction");
|
||||||
|
ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,6 +601,16 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
node.Key = "LaunchAngle";
|
node.Key = "LaunchAngle";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (engineVersion < 20161120)
|
||||||
|
{
|
||||||
|
if (node.Key.StartsWith("Warhead", StringComparison.Ordinal) && node.Value.Value == "GrantUpgrade")
|
||||||
|
{
|
||||||
|
node.Value.Value = "GrantExternalCondition";
|
||||||
|
Console.WriteLine("GrantExternalCondition Condition must be manually added to all target actor's ExternalConditions list.");
|
||||||
|
ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpgradeWeaponRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
UpgradeWeaponRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,18 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using OpenRA.Mods.Common.Traits;
|
using OpenRA.Mods.Common.Traits;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Warheads
|
namespace OpenRA.Mods.Common.Warheads
|
||||||
{
|
{
|
||||||
public class GrantUpgradeWarhead : Warhead
|
public class GrantExternalConditionWarhead : Warhead
|
||||||
{
|
{
|
||||||
[UpgradeGrantedReference]
|
[FieldLoader.Require]
|
||||||
[Desc("The upgrades to apply.")]
|
[Desc("The condition to apply. Must be included in the target actor's ExternalConditions list.")]
|
||||||
public readonly string[] Upgrades = { };
|
public readonly string Condition = null;
|
||||||
|
|
||||||
[Desc("Duration of the upgrade (in ticks). Set to 0 for a permanent upgrade.")]
|
[Desc("Duration of the condition (in ticks). Set to 0 for a permanent condition.")]
|
||||||
public readonly int Duration = 0;
|
public readonly int Duration = 0;
|
||||||
|
|
||||||
public readonly WDist Range = WDist.FromCells(1);
|
public readonly WDist Range = WDist.FromCells(1);
|
||||||
@@ -38,22 +37,10 @@ namespace OpenRA.Mods.Common.Warheads
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var um = a.TraitOrDefault<UpgradeManager>();
|
var um = a.TraitOrDefault<UpgradeManager>();
|
||||||
if (um == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var u in Upgrades)
|
// Condition token is ignored because we never revoke this condition.
|
||||||
{
|
if (um != null && um.AcceptsExternalCondition(a, Condition))
|
||||||
if (Duration > 0)
|
um.GrantCondition(a, Condition, true, Duration);
|
||||||
{
|
|
||||||
if (um.AcknowledgesUpgrade(a, u))
|
|
||||||
um.GrantTimedUpgrade(a, u, Duration, firedBy, Upgrades.Count(upg => upg == u));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (um.AcceptsUpgrade(a, u))
|
|
||||||
um.GrantUpgrade(a, u, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,6 +159,8 @@
|
|||||||
CloakSound: trans1.aud
|
CloakSound: trans1.aud
|
||||||
UncloakSound: trans1.aud
|
UncloakSound: trans1.aud
|
||||||
RequiresCondition: cloak
|
RequiresCondition: cloak
|
||||||
|
ExternalConditions@CLOAK:
|
||||||
|
Conditions: cloak
|
||||||
MustBeDestroyed:
|
MustBeDestroyed:
|
||||||
Voiced:
|
Voiced:
|
||||||
VoiceSet: VehicleVoice
|
VoiceSet: VehicleVoice
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ CRATE:
|
|||||||
ExplodeCrateAction@fire:
|
ExplodeCrateAction@fire:
|
||||||
Weapon: Napalm.Crate
|
Weapon: Napalm.Crate
|
||||||
SelectionShares: 5
|
SelectionShares: 5
|
||||||
GrantUpgradeCrateAction@cloak:
|
GrantExternalConditionCrateAction@cloak:
|
||||||
SelectionShares: 5
|
SelectionShares: 5
|
||||||
Effect: cloak
|
Effect: cloak
|
||||||
Upgrades: cloak
|
Condition: cloak
|
||||||
GiveMcvCrateAction:
|
GiveMcvCrateAction:
|
||||||
SelectionShares: 0
|
SelectionShares: 0
|
||||||
NoBaseSelectionShares: 120
|
NoBaseSelectionShares: 120
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ FTUR:
|
|||||||
BeginChargeSound: chrochr1.aud
|
BeginChargeSound: chrochr1.aud
|
||||||
EndChargeSound: chrordy1.aud
|
EndChargeSound: chrordy1.aud
|
||||||
Range: 3
|
Range: 3
|
||||||
GrantUpgradePower@IRONCURTAIN:
|
GrantExternalConditionPower@IRONCURTAIN:
|
||||||
Icon: invuln
|
Icon: invuln
|
||||||
ChargeTime: 30
|
ChargeTime: 30
|
||||||
Description: Invulnerability
|
Description: Invulnerability
|
||||||
@@ -129,8 +129,9 @@ FTUR:
|
|||||||
BeginChargeSound: ironchg1.aud
|
BeginChargeSound: ironchg1.aud
|
||||||
EndChargeSound: ironrdy1.aud
|
EndChargeSound: ironrdy1.aud
|
||||||
Range: 1
|
Range: 1
|
||||||
Upgrades: invulnerability
|
Condition: invulnerability
|
||||||
GrantUpgradeSequence: idle
|
Sequence: idle
|
||||||
|
OnFireSound: ironcur9.aud
|
||||||
Power:
|
Power:
|
||||||
Amount: 0
|
Amount: 0
|
||||||
|
|
||||||
@@ -186,7 +187,7 @@ T17:
|
|||||||
Duration: 999999
|
Duration: 999999
|
||||||
KillCargo: yes
|
KillCargo: yes
|
||||||
Range: 3
|
Range: 3
|
||||||
GrantUpgradePower@IRONCURTAIN:
|
GrantExternalConditionPower@IRONCURTAIN:
|
||||||
Icon: invuln
|
Icon: invuln
|
||||||
ChargeTime: 30
|
ChargeTime: 30
|
||||||
Description: Invulnerability
|
Description: Invulnerability
|
||||||
@@ -196,5 +197,6 @@ T17:
|
|||||||
BeginChargeSound: ironchg1.aud
|
BeginChargeSound: ironchg1.aud
|
||||||
EndChargeSound: ironrdy1.aud
|
EndChargeSound: ironrdy1.aud
|
||||||
Range: 1
|
Range: 1
|
||||||
Upgrades: invulnerability
|
Condition: invulnerability
|
||||||
GrantUpgradeSequence: idle
|
Sequence: idle
|
||||||
|
OnFireSound: ironcur9.aud
|
||||||
|
|||||||
@@ -69,11 +69,11 @@ FORTCRATE:
|
|||||||
GiveUnitCrateAction@e7:
|
GiveUnitCrateAction@e7:
|
||||||
Units: e7
|
Units: e7
|
||||||
SelectionShares: 10
|
SelectionShares: 10
|
||||||
GrantUpgradeCrateAction@ironcurtain:
|
GrantExternalConditionCrateAction@ironcurtain:
|
||||||
SelectionShares: 10
|
SelectionShares: 10
|
||||||
Effect: invuln
|
Effect: invuln
|
||||||
Notification: ironcur9.aud
|
Notification: ironcur9.aud
|
||||||
Upgrades: invulnerability
|
Condition: invulnerability
|
||||||
Duration: 1200
|
Duration: 1200
|
||||||
ExplodeCrateAction@bigboom:
|
ExplodeCrateAction@bigboom:
|
||||||
Weapon: SCUD
|
Weapon: SCUD
|
||||||
|
|||||||
@@ -121,8 +121,10 @@
|
|||||||
DamageMultiplier@IRONCURTAIN:
|
DamageMultiplier@IRONCURTAIN:
|
||||||
RequiresCondition: invulnerability
|
RequiresCondition: invulnerability
|
||||||
Modifier: 0
|
Modifier: 0
|
||||||
TimedUpgradeBar:
|
TimedConditionBar:
|
||||||
Upgrade: invulnerability
|
Condition: invulnerability
|
||||||
|
ExternalConditions@INVULNERABILITY:
|
||||||
|
Conditions: invulnerability
|
||||||
|
|
||||||
^Vehicle:
|
^Vehicle:
|
||||||
Inherits@1: ^ExistsInWorld
|
Inherits@1: ^ExistsInWorld
|
||||||
|
|||||||
@@ -90,11 +90,11 @@ CRATE:
|
|||||||
Units: e1,e1,e4,e4,e3,e3,e3
|
Units: e1,e1,e4,e4,e3,e3,e3
|
||||||
ValidFactions: soviet, russia, ukraine
|
ValidFactions: soviet, russia, ukraine
|
||||||
TimeDelay: 4500
|
TimeDelay: 4500
|
||||||
GrantUpgradeCrateAction@invuln:
|
GrantExternalConditionCrateAction@invuln:
|
||||||
SelectionShares: 5
|
SelectionShares: 5
|
||||||
Effect: invuln
|
Effect: invuln
|
||||||
Notification: ironcur9.aud
|
Notification: ironcur9.aud
|
||||||
Upgrades: invulnerability
|
Condition: invulnerability
|
||||||
Duration: 600
|
Duration: 600
|
||||||
|
|
||||||
MONEYCRATE:
|
MONEYCRATE:
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ IRON:
|
|||||||
Range: 10c0
|
Range: 10c0
|
||||||
Bib:
|
Bib:
|
||||||
HasMinibib: Yes
|
HasMinibib: Yes
|
||||||
GrantUpgradePower@IRONCURTAIN:
|
GrantExternalConditionPower@IRONCURTAIN:
|
||||||
Icon: invuln
|
Icon: invuln
|
||||||
ChargeTime: 120
|
ChargeTime: 120
|
||||||
Description: Invulnerability
|
Description: Invulnerability
|
||||||
@@ -314,7 +314,8 @@ IRON:
|
|||||||
BeginChargeSpeechNotification: IronCurtainCharging
|
BeginChargeSpeechNotification: IronCurtainCharging
|
||||||
EndChargeSpeechNotification: IronCurtainReady
|
EndChargeSpeechNotification: IronCurtainReady
|
||||||
DisplayRadarPing: True
|
DisplayRadarPing: True
|
||||||
Upgrades: invulnerability
|
Condition: invulnerability
|
||||||
|
OnFireSound: ironcur9.aud
|
||||||
SupportPowerChargeBar:
|
SupportPowerChargeBar:
|
||||||
Power:
|
Power:
|
||||||
Amount: -200
|
Amount: -200
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ BUS:
|
|||||||
MaxWeight: 20
|
MaxWeight: 20
|
||||||
PipCount: 5
|
PipCount: 5
|
||||||
UnloadVoice: Unload
|
UnloadVoice: Unload
|
||||||
LoadingUpgrades: notmobile
|
LoadingUpgrades: loading
|
||||||
EjectOnDeath: true
|
EjectOnDeath: true
|
||||||
|
|
||||||
PICK:
|
PICK:
|
||||||
@@ -126,7 +126,7 @@ PICK:
|
|||||||
MaxWeight: 2
|
MaxWeight: 2
|
||||||
PipCount: 5
|
PipCount: 5
|
||||||
UnloadVoice: Unload
|
UnloadVoice: Unload
|
||||||
LoadingUpgrades: notmobile
|
LoadingUpgrades: loading
|
||||||
EjectOnDeath: true
|
EjectOnDeath: true
|
||||||
|
|
||||||
CAR:
|
CAR:
|
||||||
@@ -150,7 +150,7 @@ CAR:
|
|||||||
MaxWeight: 4
|
MaxWeight: 4
|
||||||
PipCount: 5
|
PipCount: 5
|
||||||
UnloadVoice: Unload
|
UnloadVoice: Unload
|
||||||
LoadingUpgrades: notmobile
|
LoadingUpgrades: loading
|
||||||
EjectOnDeath: true
|
EjectOnDeath: true
|
||||||
|
|
||||||
WINI:
|
WINI:
|
||||||
@@ -174,7 +174,7 @@ WINI:
|
|||||||
MaxWeight: 5
|
MaxWeight: 5
|
||||||
PipCount: 5
|
PipCount: 5
|
||||||
UnloadVoice: Unload
|
UnloadVoice: Unload
|
||||||
LoadingUpgrades: notmobile
|
LoadingUpgrades: loading
|
||||||
EjectOnDeath: true
|
EjectOnDeath: true
|
||||||
|
|
||||||
LOCOMOTIVE:
|
LOCOMOTIVE:
|
||||||
|
|||||||
@@ -64,6 +64,8 @@
|
|||||||
ReferencePoint: Bottom, Right
|
ReferencePoint: Bottom, Right
|
||||||
RequiresCondition: rank-elite
|
RequiresCondition: rank-elite
|
||||||
ZOffset: 256
|
ZOffset: 256
|
||||||
|
ExternalConditions@CRATES:
|
||||||
|
Conditions: crate-firepower, crate-damage, crate-speed, crate-cloak
|
||||||
|
|
||||||
^EmpDisable:
|
^EmpDisable:
|
||||||
UpgradeOverlay@EMPDISABLE:
|
UpgradeOverlay@EMPDISABLE:
|
||||||
@@ -71,8 +73,8 @@
|
|||||||
Palette: disabled
|
Palette: disabled
|
||||||
DisableOnUpgrade@EMPDISABLE:
|
DisableOnUpgrade@EMPDISABLE:
|
||||||
RequiresCondition: empdisable
|
RequiresCondition: empdisable
|
||||||
TimedUpgradeBar@EMPDISABLE:
|
TimedConditionBar@EMPDISABLE:
|
||||||
Upgrade: empdisable
|
Condition: empdisable
|
||||||
Color: FFFFFF
|
Color: FFFFFF
|
||||||
WithIdleOverlay@EMPDISABLE:
|
WithIdleOverlay@EMPDISABLE:
|
||||||
Sequence: emp-overlay
|
Sequence: emp-overlay
|
||||||
@@ -83,11 +85,13 @@
|
|||||||
PowerMultiplier@EMPDISABLE:
|
PowerMultiplier@EMPDISABLE:
|
||||||
RequiresCondition: empdisable
|
RequiresCondition: empdisable
|
||||||
Modifier: 0
|
Modifier: 0
|
||||||
|
ExternalConditions@EMPDISABLE:
|
||||||
|
Conditions: empdisable
|
||||||
|
|
||||||
^EmpDisableMobile:
|
^EmpDisableMobile:
|
||||||
Inherits: ^EmpDisable
|
Inherits: ^EmpDisable
|
||||||
Mobile:
|
Mobile:
|
||||||
RequiresCondition: !notmobile
|
RequiresCondition: !empdisable && !deployed && !loading
|
||||||
|
|
||||||
^Cloakable:
|
^Cloakable:
|
||||||
Cloak@CLOAKGENERATOR:
|
Cloak@CLOAKGENERATOR:
|
||||||
@@ -639,7 +643,6 @@
|
|||||||
Mobile:
|
Mobile:
|
||||||
Speed: 113
|
Speed: 113
|
||||||
TurnSpeed: 16
|
TurnSpeed: 16
|
||||||
Crushes: crate
|
|
||||||
SharesCell: no
|
SharesCell: no
|
||||||
TerrainSpeeds:
|
TerrainSpeeds:
|
||||||
Clear: 90
|
Clear: 90
|
||||||
@@ -795,7 +798,7 @@
|
|||||||
Cargo:
|
Cargo:
|
||||||
Types: Infantry
|
Types: Infantry
|
||||||
UnloadVoice: Unload
|
UnloadVoice: Unload
|
||||||
LoadingUpgrades: notmobile
|
LoadingUpgrades: loading
|
||||||
Health:
|
Health:
|
||||||
HP: 100
|
HP: 100
|
||||||
Armor:
|
Armor:
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ APC:
|
|||||||
MaxWeight: 5
|
MaxWeight: 5
|
||||||
PipCount: 5
|
PipCount: 5
|
||||||
UnloadVoice: Unload
|
UnloadVoice: Unload
|
||||||
LoadingUpgrades: notmobile
|
LoadingUpgrades: loading
|
||||||
EjectOnDeath: true
|
EjectOnDeath: true
|
||||||
UpgradeOnTerrain:
|
UpgradeOnTerrain:
|
||||||
Upgrades: inwater
|
Upgrades: inwater
|
||||||
|
|||||||
@@ -74,24 +74,24 @@ CRATE:
|
|||||||
SelectionShares: 0
|
SelectionShares: 0
|
||||||
NoBaseSelectionShares: 100
|
NoBaseSelectionShares: 100
|
||||||
Units: mcv
|
Units: mcv
|
||||||
GrantUpgradeCrateAction@cloak:
|
GrantExternalConditionCrateAction@cloak:
|
||||||
SelectionShares: 5
|
SelectionShares: 5
|
||||||
Effect: stealth
|
Effect: stealth
|
||||||
Upgrades: crate-cloak
|
Condition: crate-cloak
|
||||||
Notification: cloak5.aud
|
Notification: cloak5.aud
|
||||||
GrantUpgradeCrateAction@firepower:
|
GrantExternalConditionCrateAction@firepower:
|
||||||
SelectionShares: 5
|
SelectionShares: 5
|
||||||
Effect: firepower
|
Effect: firepower
|
||||||
Upgrades: crate-firepower
|
Condition: crate-firepower
|
||||||
Notification: 00-i070.aud
|
Notification: 00-i070.aud
|
||||||
GrantUpgradeCrateAction@armor:
|
GrantExternalConditionCrateAction@armor:
|
||||||
SelectionShares: 5
|
SelectionShares: 5
|
||||||
Effect: armor
|
Effect: armor
|
||||||
Upgrades: crate-damage
|
Condition: crate-damage
|
||||||
Notification: 00-i068.aud
|
Notification: 00-i068.aud
|
||||||
GrantUpgradeCrateAction@speed:
|
GrantExternalConditionCrateAction@speed:
|
||||||
SelectionShares: 5
|
SelectionShares: 5
|
||||||
Upgrades: crate-speed
|
Condition: crate-speed
|
||||||
Notification: 00-i080.aud
|
Notification: 00-i080.aud
|
||||||
|
|
||||||
SROCK01:
|
SROCK01:
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ TTNK:
|
|||||||
RenderSprites:
|
RenderSprites:
|
||||||
Image: ttnk
|
Image: ttnk
|
||||||
DeployToUpgrade:
|
DeployToUpgrade:
|
||||||
DeployedUpgrades: deployed, notmobile
|
DeployedUpgrades: deployed
|
||||||
UndeployedUpgrades: undeployed
|
UndeployedUpgrades: undeployed
|
||||||
DeployAnimation: make
|
DeployAnimation: make
|
||||||
Facing: 160
|
Facing: 160
|
||||||
@@ -285,7 +285,7 @@ SAPC:
|
|||||||
MaxWeight: 5
|
MaxWeight: 5
|
||||||
PipCount: 5
|
PipCount: 5
|
||||||
UnloadVoice: Unload
|
UnloadVoice: Unload
|
||||||
LoadingUpgrades: notmobile
|
LoadingUpgrades: loading
|
||||||
EjectOnDeath: true
|
EjectOnDeath: true
|
||||||
|
|
||||||
SUBTANK:
|
SUBTANK:
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ LPST:
|
|||||||
gdi: lpst.gdi
|
gdi: lpst.gdi
|
||||||
nod: lpst.nod
|
nod: lpst.nod
|
||||||
DeployToUpgrade:
|
DeployToUpgrade:
|
||||||
DeployedUpgrades: deployed, notmobile
|
DeployedUpgrades: deployed
|
||||||
UndeployedUpgrades: undeployed
|
UndeployedUpgrades: undeployed
|
||||||
DeployAnimation: make
|
DeployAnimation: make
|
||||||
Facing: 160
|
Facing: 160
|
||||||
|
|||||||
@@ -107,10 +107,10 @@ EMPulseCannon:
|
|||||||
Image: pulsball
|
Image: pulsball
|
||||||
Warhead@1Eff: CreateEffect
|
Warhead@1Eff: CreateEffect
|
||||||
Explosions: pulse_explosion
|
Explosions: pulse_explosion
|
||||||
Warhead@emp: GrantUpgrade
|
Warhead@emp: GrantExternalCondition
|
||||||
Range: 4c0
|
Range: 4c0
|
||||||
Duration: 250
|
Duration: 250
|
||||||
Upgrades: empdisable, notmobile
|
Condition: empdisable
|
||||||
|
|
||||||
ClusterMissile:
|
ClusterMissile:
|
||||||
ValidTargets: Ground, Water, Air
|
ValidTargets: Ground, Water, Air
|
||||||
|
|||||||
Reference in New Issue
Block a user