Add support for per-source and total external condition caps.
This commit is contained in:
@@ -777,7 +777,7 @@
|
||||
<Compile Include="Traits\AutoCarryall.cs" />
|
||||
<Compile Include="Traits\World\CliffBackImpassabilityLayer.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantCondition.cs" />
|
||||
<Compile Include="Traits\Conditions\ExternalConditions.cs" />
|
||||
<Compile Include="Traits\Conditions\ExternalCondition.cs" />
|
||||
<Compile Include="Traits\Conditions\StackedCondition.cs" />
|
||||
<Compile Include="Traits\Buildings\BridgeHut.cs" />
|
||||
<Compile Include="Traits\Buildings\BridgePlaceholder.cs" />
|
||||
|
||||
@@ -20,15 +20,16 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.Common.Scripting
|
||||
{
|
||||
[ScriptPropertyGroup("General")]
|
||||
public class ConditionProperties : ScriptActorProperties, Requires<ConditionManagerInfo>
|
||||
public class ConditionProperties : ScriptActorProperties, Requires<ExternalConditionInfo>
|
||||
{
|
||||
readonly ConditionManager conditionManager;
|
||||
readonly ExternalCondition[] externalConditions;
|
||||
|
||||
readonly Dictionary<string, Stack<int>> legacyShim = new Dictionary<string, Stack<int>>();
|
||||
|
||||
public ConditionProperties(ScriptContext context, Actor self)
|
||||
: base(context, self)
|
||||
{
|
||||
conditionManager = self.Trait<ConditionManager>();
|
||||
externalConditions = self.TraitsImplementing<ExternalCondition>().ToArray();
|
||||
}
|
||||
|
||||
[Desc("Grant an external condition on this actor and return the revocation token.",
|
||||
@@ -36,22 +37,27 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
"If duration > 0 the condition will be automatically revoked after the defined number of ticks")]
|
||||
public int GrantCondition(string condition, int duration = 0)
|
||||
{
|
||||
if (!conditionManager.AcceptsExternalCondition(Self, condition, duration > 0))
|
||||
throw new InvalidDataException("Condition `{0}` has not been listed on an ExternalConditions trait".F(condition));
|
||||
var external = externalConditions
|
||||
.FirstOrDefault(t => t.Info.Condition == condition && t.CanGrantCondition(Self, this));
|
||||
|
||||
return conditionManager.GrantCondition(Self, condition, true, duration);
|
||||
if (external == null)
|
||||
throw new InvalidDataException("Condition `{0}` has not been listed on an enabled ExternalCondition trait".F(condition));
|
||||
|
||||
return external.GrantCondition(Self, this, duration);
|
||||
}
|
||||
|
||||
[Desc("Revoke a condition using the token returned by GrantCondition.")]
|
||||
public void RevokeCondition(int token)
|
||||
{
|
||||
conditionManager.RevokeCondition(Self, token);
|
||||
foreach (var external in externalConditions)
|
||||
external.TryRevokeCondition(Self, this, token);
|
||||
}
|
||||
|
||||
[Desc("Check whether this actor accepts a specific external condition.")]
|
||||
public bool AcceptsCondition(string condition, bool timed = false)
|
||||
public bool AcceptsCondition(string condition)
|
||||
{
|
||||
return conditionManager.AcceptsExternalCondition(Self, condition, timed);
|
||||
return externalConditions
|
||||
.Any(t => t.Info.Condition == condition && t.CanGrantCondition(Self, this));
|
||||
}
|
||||
|
||||
[Desc("Grant an upgrade to this actor. DEPRECATED! Will be removed.")]
|
||||
|
||||
@@ -63,9 +63,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
/// <summary>Each granted condition receives a unique token that is used when revoking.</summary>
|
||||
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[]>();
|
||||
|
||||
@@ -114,12 +111,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
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;
|
||||
@@ -172,11 +163,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
/// <returns>The token that is used to revoke this condition.</returns>
|
||||
/// <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)
|
||||
public int GrantCondition(Actor self, string condition, int duration = 0)
|
||||
{
|
||||
if (external && !externalConditions.Contains(condition))
|
||||
return InvalidConditionToken;
|
||||
|
||||
var token = nextToken++;
|
||||
tokens.Add(token, condition);
|
||||
|
||||
@@ -218,26 +206,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
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, bool timed = false)
|
||||
{
|
||||
if (state == null)
|
||||
throw new InvalidOperationException("AcceptsExternalCondition cannot be queried before the actor has been fully created.");
|
||||
|
||||
if (!externalConditions.Contains(condition))
|
||||
return false;
|
||||
|
||||
// A timed condition can always replace an existing timed condition (resetting its duration)
|
||||
if (timed && timers.ContainsKey(condition))
|
||||
return true;
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
142
OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs
Normal file
142
OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Allows a condition to be granted from an external source (Lua, warheads, etc).")]
|
||||
public class ExternalConditionInfo : ITraitInfo, Requires<ConditionManagerInfo>
|
||||
{
|
||||
[GrantedConditionReference]
|
||||
[FieldLoader.Require]
|
||||
public readonly string Condition = null;
|
||||
|
||||
[Desc("If > 0, restrict the number of times that this condition can be granted by a single source.")]
|
||||
public readonly int SourceCap = 0;
|
||||
|
||||
[Desc("If > 0, restrict the number of times that this condition can be granted by any source.")]
|
||||
public readonly int TotalCap = 0;
|
||||
|
||||
public object Create(ActorInitializer init) { return new ExternalCondition(init.Self, this); }
|
||||
}
|
||||
|
||||
public class ExternalCondition
|
||||
{
|
||||
class TimedToken
|
||||
{
|
||||
public int Token;
|
||||
public int Expires;
|
||||
}
|
||||
|
||||
public readonly ExternalConditionInfo Info;
|
||||
readonly ConditionManager conditionManager;
|
||||
readonly Dictionary<object, HashSet<int>> permanentTokens = new Dictionary<object, HashSet<int>>();
|
||||
readonly Dictionary<object, HashSet<TimedToken>> timedTokens = new Dictionary<object, HashSet<TimedToken>>();
|
||||
|
||||
public ExternalCondition(Actor self, ExternalConditionInfo info)
|
||||
{
|
||||
Info = info;
|
||||
conditionManager = self.Trait<ConditionManager>();
|
||||
}
|
||||
|
||||
public bool CanGrantCondition(Actor self, object source)
|
||||
{
|
||||
if (conditionManager == null || source == null)
|
||||
return false;
|
||||
|
||||
// Timed tokens do not count towards the source cap: the condition with the shortest
|
||||
// remaining duration can always be revoked to make room.
|
||||
if (Info.SourceCap > 0 && permanentTokens.GetOrAdd(source).Count >= Info.SourceCap)
|
||||
return false;
|
||||
|
||||
if (Info.TotalCap > 0 && permanentTokens.Values.SelectMany(t => t).Count() >= Info.TotalCap)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GrantCondition(Actor self, object source, int duration = 0)
|
||||
{
|
||||
if (conditionManager == null || source == null || !CanGrantCondition(self, source))
|
||||
return ConditionManager.InvalidConditionToken;
|
||||
|
||||
var token = conditionManager.GrantCondition(self, Info.Condition, duration);
|
||||
var permanent = permanentTokens.GetOrAdd(source);
|
||||
|
||||
if (duration > 0)
|
||||
{
|
||||
var timed = timedTokens.GetOrAdd(source);
|
||||
|
||||
// Remove expired tokens
|
||||
timed.RemoveWhere(t => t.Expires < self.World.WorldTick);
|
||||
|
||||
// Check level caps
|
||||
if (Info.SourceCap > 0)
|
||||
{
|
||||
if (permanent.Count + timed.Count >= Info.SourceCap)
|
||||
{
|
||||
var expire = timed.MinByOrDefault(t => t.Expires);
|
||||
if (expire != null)
|
||||
{
|
||||
timed.Remove(expire);
|
||||
if (conditionManager.TokenValid(self, expire.Token))
|
||||
conditionManager.RevokeCondition(self, expire.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Info.TotalCap > 0)
|
||||
{
|
||||
var totalCount = permanentTokens.Values.SelectMany(t => t).Count() + timedTokens.Values.SelectMany(t => t).Count();
|
||||
if (totalCount >= Info.TotalCap)
|
||||
{
|
||||
// Prefer tokens from the same source
|
||||
var expire = timedTokens.SelectMany(t => t.Value.Select(tt => new Tuple<object, TimedToken>(t.Key, tt)))
|
||||
.MinByOrDefault(t => t.Item2.Expires);
|
||||
if (expire != null)
|
||||
{
|
||||
if (conditionManager.TokenValid(self, expire.Item2.Token))
|
||||
conditionManager.RevokeCondition(self, expire.Item2.Token);
|
||||
|
||||
timedTokens[expire.Item1].Remove(expire.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timed.Add(new TimedToken { Expires = self.World.WorldTick + duration, Token = token });
|
||||
}
|
||||
else
|
||||
permanent.Add(token);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/// <summary>Revokes the external condition with the given token if it was granted by this trait.</summary>
|
||||
/// <returns><c>true</c> if the now-revoked condition was originally granted by this trait.</returns>
|
||||
public bool TryRevokeCondition(Actor self, object source, int token)
|
||||
{
|
||||
if (conditionManager == null || source == null)
|
||||
return false;
|
||||
|
||||
var removed = permanentTokens.GetOrAdd(source).Remove(token) ||
|
||||
timedTokens.GetOrAdd(source).RemoveWhere(t => t.Token == token) > 0;
|
||||
|
||||
if (removed && conditionManager.TokenValid(self, token))
|
||||
conditionManager.RevokeCondition(self, token);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 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>
|
||||
{
|
||||
[GrantedConditionReference]
|
||||
public readonly string[] Conditions = { };
|
||||
}
|
||||
|
||||
public class ExternalConditions { }
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -104,13 +105,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (a == self && !info.AffectsParent)
|
||||
return;
|
||||
|
||||
if (tokens.ContainsKey(a))
|
||||
return;
|
||||
|
||||
var stance = self.Owner.Stances[a.Owner];
|
||||
if (!info.ValidStances.HasStance(stance))
|
||||
return;
|
||||
|
||||
var cm = a.TraitOrDefault<ConditionManager>();
|
||||
if (cm != null && !tokens.ContainsKey(a) && cm.AcceptsExternalCondition(a, info.Condition))
|
||||
tokens[a] = cm.GrantCondition(a, info.Condition, true);
|
||||
var external = a.TraitsImplementing<ExternalCondition>()
|
||||
.FirstOrDefault(t => t.Info.Condition == info.Condition && t.CanGrantCondition(a, self));
|
||||
|
||||
if (external != null)
|
||||
tokens[a] = external.GrantCondition(a, self);
|
||||
}
|
||||
|
||||
public void UnitProducedByOther(Actor self, Actor producer, Actor produced)
|
||||
@@ -130,9 +136,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!info.ValidStances.HasStance(stance))
|
||||
return;
|
||||
|
||||
var cm = produced.TraitOrDefault<ConditionManager>();
|
||||
if (cm != null && cm.AcceptsExternalCondition(produced, info.Condition))
|
||||
tokens[produced] = cm.GrantCondition(produced, info.Condition, true);
|
||||
var external = produced.TraitsImplementing<ExternalCondition>()
|
||||
.FirstOrDefault(t => t.Info.Condition == info.Condition && t.CanGrantCondition(produced, self));
|
||||
|
||||
if (external != null)
|
||||
tokens[produced] = external.GrantCondition(produced, self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,9 +154,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return;
|
||||
|
||||
tokens.Remove(a);
|
||||
var cm = a.TraitOrDefault<ConditionManager>();
|
||||
if (cm != null)
|
||||
cm.RevokeCondition(a, token);
|
||||
foreach (var external in a.TraitsImplementing<ExternalCondition>())
|
||||
external.TryRevokeCondition(a, self, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
bool AcceptsCondition(Actor a)
|
||||
{
|
||||
var cm = a.TraitOrDefault<ConditionManager>();
|
||||
return cm != null && cm.AcceptsExternalCondition(a, info.Condition, info.Duration > 0);
|
||||
return a.TraitsImplementing<ExternalCondition>()
|
||||
.Any(t => t.Info.Condition == info.Condition && t.CanGrantCondition(a, self));
|
||||
}
|
||||
|
||||
public override int GetSelectionShares(Actor collector)
|
||||
@@ -71,11 +71,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!a.IsInWorld || a.IsDead)
|
||||
continue;
|
||||
|
||||
var cm = a.TraitOrDefault<ConditionManager>();
|
||||
var external = a.TraitsImplementing<ExternalCondition>()
|
||||
.FirstOrDefault(t => t.Info.Condition == info.Condition && t.CanGrantCondition(a, self));
|
||||
|
||||
// Condition token is ignored because we never revoke this condition.
|
||||
if (cm != null)
|
||||
cm.GrantCondition(a, info.Condition, true, info.Duration);
|
||||
if (external != null)
|
||||
external.GrantCondition(a, self, info.Duration);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -69,11 +69,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
foreach (var a in UnitsInRange(order.TargetLocation))
|
||||
{
|
||||
var cm = a.TraitOrDefault<ConditionManager>();
|
||||
var external = a.TraitsImplementing<ExternalCondition>()
|
||||
.FirstOrDefault(t => t.Info.Condition == info.Condition && t.CanGrantCondition(a, self));
|
||||
|
||||
// Condition token is ignored because we never revoke this condition.
|
||||
if (cm != null)
|
||||
cm.GrantCondition(a, info.Condition, true, info.Duration);
|
||||
if (external != null)
|
||||
external.GrantCondition(a, self, info.Duration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +90,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!a.Owner.IsAlliedWith(Self.Owner))
|
||||
return false;
|
||||
|
||||
var cm = a.TraitOrDefault<ConditionManager>();
|
||||
return cm != null && cm.AcceptsExternalCondition(a, info.Condition, info.Duration > 0);
|
||||
return a.TraitsImplementing<ExternalCondition>()
|
||||
.Any(t => t.Info.Condition == info.Condition && t.CanGrantCondition(a, Self));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -850,6 +850,24 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20170218)
|
||||
{
|
||||
var externalConditions = node.Value.Nodes.Where(n => n.Key.StartsWith("ExternalConditions", StringComparison.Ordinal));
|
||||
foreach (var ec in externalConditions.ToList())
|
||||
{
|
||||
var conditionsNode = ec.Value.Nodes.FirstOrDefault(n => n.Key == "Conditions");
|
||||
if (conditionsNode != null)
|
||||
{
|
||||
var conditions = FieldLoader.GetValue<string[]>("", conditionsNode.Value.Value);
|
||||
foreach (var c in conditions)
|
||||
node.Value.Nodes.Add(new MiniYamlNode("ExternalCondition@" + c.ToUpperInvariant(),
|
||||
new MiniYaml("", new List<MiniYamlNode>() { new MiniYamlNode("Condition", c) })));
|
||||
|
||||
node.Value.Nodes.Remove(ec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -36,11 +37,11 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
if (!IsValidAgainst(a, firedBy))
|
||||
continue;
|
||||
|
||||
var cm = a.TraitOrDefault<ConditionManager>();
|
||||
var external = a.TraitsImplementing<ExternalCondition>()
|
||||
.FirstOrDefault(t => t.Info.Condition == Condition && t.CanGrantCondition(a, firedBy));
|
||||
|
||||
// Condition token is ignored because we never revoke this condition.
|
||||
if (cm != null && cm.AcceptsExternalCondition(a, Condition, Duration > 0))
|
||||
cm.GrantCondition(a, Condition, true, Duration);
|
||||
if (external != null)
|
||||
external.GrantCondition(a, firedBy, Duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +123,8 @@
|
||||
CloakSound: trans1.aud
|
||||
UncloakSound: trans1.aud
|
||||
RequiresCondition: cloak
|
||||
ExternalConditions@CLOAK:
|
||||
Conditions: cloak
|
||||
ExternalCondition@CLOAK:
|
||||
Condition: cloak
|
||||
|
||||
^Vehicle:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
|
||||
@@ -34,20 +34,20 @@ HACKE6:
|
||||
CaptureTypes: building
|
||||
Targetable:
|
||||
RequiresCondition: !jail
|
||||
ExternalConditions@JAIL:
|
||||
Conditions: jail
|
||||
Targetable@PRISONER:
|
||||
TargetTypes: Prisoner
|
||||
RenderSprites:
|
||||
Image: E6
|
||||
ExternalCondition@JAIL:
|
||||
Condition: jail
|
||||
|
||||
MEDI:
|
||||
Targetable:
|
||||
RequiresCondition: !jail
|
||||
ExternalConditions@JAIL:
|
||||
Conditions: jail
|
||||
Targetable@PRISONER:
|
||||
TargetTypes: Prisoner
|
||||
ExternalCondition@JAIL:
|
||||
Condition: jail
|
||||
|
||||
PRISON:
|
||||
HiddenUnderShroud:
|
||||
|
||||
@@ -35,20 +35,20 @@ HACKE6:
|
||||
WithInfantryBody:
|
||||
Targetable:
|
||||
RequiresCondition: !jail
|
||||
ExternalConditions@JAIL:
|
||||
Conditions: jail
|
||||
Targetable@PRISONER:
|
||||
TargetTypes: Prisoner
|
||||
RenderSprites:
|
||||
Image: E6
|
||||
ExternalCondition@JAIL:
|
||||
Condition: jail
|
||||
|
||||
MEDI:
|
||||
Targetable:
|
||||
RequiresCondition: !jail
|
||||
ExternalConditions@JAIL:
|
||||
Conditions: jail
|
||||
Targetable@PRISONER:
|
||||
TargetTypes: Prisoner
|
||||
ExternalCondition@JAIL:
|
||||
Condition: jail
|
||||
|
||||
PRISON:
|
||||
HiddenUnderShroud:
|
||||
|
||||
@@ -22,8 +22,8 @@ World:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
|
||||
^Tank:
|
||||
GivesBounty:
|
||||
@@ -33,8 +33,8 @@ World:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
|
||||
^Infantry:
|
||||
GivesBounty:
|
||||
@@ -50,8 +50,8 @@ World:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
|
||||
^Ship:
|
||||
GivesBounty:
|
||||
@@ -61,8 +61,8 @@ World:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
|
||||
^Plane:
|
||||
GivesBounty:
|
||||
@@ -70,8 +70,8 @@ World:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
|
||||
^Building:
|
||||
GivesBounty:
|
||||
@@ -79,8 +79,8 @@ World:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
|
||||
OILB:
|
||||
CashTrickler:
|
||||
|
||||
@@ -59,8 +59,14 @@ V05:
|
||||
DOG:
|
||||
# HACK: Disable experience without killing the linter
|
||||
-GainsExperience:
|
||||
ExternalConditions@EXPERIENCE:
|
||||
Conditions: rank-veteran-1, rank-veteran-2, rank-veteran-3, rank-elite
|
||||
ExternalCondition@RANK-VETERAN-1:
|
||||
Condition: rank-veteran-1
|
||||
ExternalCondition@RANK-VETERAN-2:
|
||||
Condition: rank-veteran-2
|
||||
ExternalCondition@RANK-VETERAN-3:
|
||||
Condition: rank-veteran-3
|
||||
ExternalCondition@RANK-ELITE:
|
||||
Condition: rank-elite
|
||||
|
||||
SPY:
|
||||
Mobile:
|
||||
|
||||
@@ -123,8 +123,8 @@
|
||||
Modifier: 0
|
||||
TimedConditionBar:
|
||||
Condition: invulnerability
|
||||
ExternalConditions@INVULNERABILITY:
|
||||
Conditions: invulnerability
|
||||
ExternalCondition@INVULNERABILITY:
|
||||
Condition: invulnerability
|
||||
|
||||
^Vehicle:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
|
||||
@@ -539,8 +539,6 @@ DOME:
|
||||
Bib:
|
||||
ProvidesRadar:
|
||||
RequiresCondition: !jammed && !disabled
|
||||
ExternalConditions@JAMMED:
|
||||
Conditions: jammed
|
||||
InfiltrateForExploration:
|
||||
DetectCloaked:
|
||||
Range: 10c0
|
||||
@@ -550,6 +548,8 @@ DOME:
|
||||
ProvidesPrerequisite@buildingname:
|
||||
GrantConditionOnDisabled@IDISABLE:
|
||||
Condition: disabled
|
||||
ExternalCondition@JAMMED:
|
||||
Condition: jammed
|
||||
|
||||
PBOX:
|
||||
Inherits: ^Defense
|
||||
|
||||
@@ -1448,17 +1448,17 @@ Rules:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
NAOBEL:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
NALASR:
|
||||
DamageMultiplier@UNKILLABLE:
|
||||
RequiresCondition: unkillable
|
||||
Modifier: 0
|
||||
ExternalConditions:
|
||||
Conditions: unkillable
|
||||
ExternalCondition@UNKILLABLE:
|
||||
Condition: unkillable
|
||||
|
||||
@@ -1296,7 +1296,8 @@ GALITE:
|
||||
SelectionDecorations:
|
||||
VisualBounds: 25, 35, 0, -12
|
||||
-Cloak@EXTERNALCLOAK:
|
||||
-ExternalConditions@EXTERNALCLOAK:
|
||||
-ExternalCondition@CLOAKGENERATOR:
|
||||
-ExternalCondition@CRATE-CLOAK:
|
||||
|
||||
TSTLAMP:
|
||||
Inherits: GALITE
|
||||
|
||||
@@ -75,8 +75,12 @@
|
||||
SpeedMultiplier@CRATES:
|
||||
RequiresCondition: crate-speed
|
||||
Modifier: 170
|
||||
ExternalConditions@CRATES:
|
||||
Conditions: crate-firepower, crate-damage, crate-speed
|
||||
ExternalCondition@CRATE-FIREPOWER:
|
||||
Condition: crate-firepower
|
||||
ExternalCondition@CRATE-DAMAGE:
|
||||
Condition: crate-damage
|
||||
ExternalCondition@CRATE-SPEED:
|
||||
Condition: crate-speed
|
||||
|
||||
^EmpDisable:
|
||||
WithColoredOverlay@EMPDISABLE:
|
||||
@@ -96,8 +100,8 @@
|
||||
PowerMultiplier@EMPDISABLE:
|
||||
RequiresCondition: empdisable
|
||||
Modifier: 0
|
||||
ExternalConditions@EMPDISABLE:
|
||||
Conditions: empdisable
|
||||
ExternalCondition@EMPDISABLE:
|
||||
Condition: empdisable
|
||||
|
||||
^Cloakable:
|
||||
Cloak@EXTERNALCLOAK:
|
||||
@@ -108,8 +112,10 @@
|
||||
CloakSound: cloak5.aud
|
||||
UncloakSound: cloak5.aud
|
||||
UncloakOn: Attack, Unload, Infiltrate, Demolish, Damage
|
||||
ExternalConditions@EXTERNALCLOAK:
|
||||
Conditions: cloakgenerator, crate-cloak
|
||||
ExternalCondition@CLOAKGENERATOR:
|
||||
Condition: cloakgenerator
|
||||
ExternalCondition@CRATE-CLOAK:
|
||||
Condition: crate-cloak
|
||||
|
||||
^BasicBuilding:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
@@ -206,7 +212,8 @@
|
||||
RenderSprites:
|
||||
Palette: player
|
||||
-Cloak@EXTERNALCLOAK:
|
||||
-ExternalConditions@EXTERNALCLOAK:
|
||||
-ExternalCondition@CLOAKGENERATOR:
|
||||
-ExternalCondition@CRATE-CLOAK:
|
||||
|
||||
^CivBillboard:
|
||||
Inherits: ^CivBuilding
|
||||
|
||||
Reference in New Issue
Block a user