diff --git a/OpenRA.Game/GameRules/Warhead.cs b/OpenRA.Game/GameRules/Warhead.cs index 043e5772e6..95316875ea 100644 --- a/OpenRA.Game/GameRules/Warhead.cs +++ b/OpenRA.Game/GameRules/Warhead.cs @@ -23,12 +23,20 @@ namespace OpenRA.GameRules [Desc("What types of targets are unaffected.", "Overrules ValidTargets.")] public readonly string[] InvalidTargets = { }; + + [Desc("What diplomatic stances are affected.")] + public readonly Stance ValidStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + + [Desc("Can this warhead affect the actor that fired it.")] + public readonly bool AffectsParent = false; [Desc("Delay in ticks before applying the warhead effect.","0 = instant (old model).")] public readonly int Delay = 0; + ///Applies the warhead's effect against the target. public abstract void DoImpact(Target target, Actor firedBy, IEnumerable damageModifiers); + ///Checks if the warhead is valid against (can do something to) the target. public bool IsValidAgainst(Target target, World world, Actor firedBy) { if (target.Type == TargetType.Actor) @@ -58,53 +66,46 @@ namespace OpenRA.GameRules // assumption has been removed from the yaml definitions public virtual bool CanTargetActor(ActorInfo victim, Actor firedBy) { return false; } + ///Checks if the warhead is valid against (can do something to) the actor. public bool IsValidAgainst(Actor victim, Actor firedBy) { if (!CanTargetActor(victim.Info, firedBy)) return false; + if (!AffectsParent && victim == firedBy) + return false; + + var stance = firedBy.Owner.Stances[victim.Owner]; + if (!ValidStances.HasFlag(stance)) + return false; + // A target type is valid if it is in the valid targets list, and not in the invalid targets list. - return InTargetList(victim, firedBy, ValidTargets) && - !InTargetList(victim, firedBy, InvalidTargets); - } - - public static bool InTargetList(Actor victim, Actor firedBy, string[] targetList) - { - if (!targetList.Any()) - return false; - var targetable = victim.TraitOrDefault(); - if (targetable == null) - return false; - if (!targetList.Intersect(targetable.TargetTypes).Any()) + if (targetable == null || !ValidTargets.Intersect(targetable.TargetTypes).Any() + || InvalidTargets.Intersect(targetable.TargetTypes).Any()) return false; return true; } + ///Checks if the warhead is valid against (can do something to) the frozen actor. public bool IsValidAgainst(FrozenActor victim, Actor firedBy) { if (!CanTargetActor(victim.Info, firedBy)) return false; + // AffectsParent checks do not make sense for FrozenActors, so skip to stance checks + var stance = firedBy.Owner.Stances[victim.Owner]; + if (!ValidStances.HasFlag(stance)) + return false; + // A target type is valid if it is in the valid targets list, and not in the invalid targets list. - return InTargetList(victim, firedBy, ValidTargets) && - !InTargetList(victim, firedBy, InvalidTargets); - } - - public static bool InTargetList(FrozenActor victim, Actor firedBy, string[] targetList) - { - // Frozen Actors need to be handled slightly differently. Since FrozenActor.Actor can be null if the Actor is dead. - if (!targetList.Any()) - return false; - var targetable = victim.Info.Traits.GetOrDefault(); - if (targetable == null) + if (targetable == null || !ValidTargets.Intersect(targetable.GetTargetTypes()).Any() + || InvalidTargets.Intersect(targetable.GetTargetTypes()).Any()) return false; - if (!targetList.Intersect(targetable.GetTargetTypes()).Any()) - return false; - + return true; } - } + } } diff --git a/OpenRA.Game/GameRules/WeaponInfo.cs b/OpenRA.Game/GameRules/WeaponInfo.cs index 6a40d3186b..567d0602c9 100644 --- a/OpenRA.Game/GameRules/WeaponInfo.cs +++ b/OpenRA.Game/GameRules/WeaponInfo.cs @@ -92,6 +92,7 @@ namespace OpenRA.GameRules return retList; } + ///Checks if the weapon is valid against (can target) the target. public bool IsValidAgainst(Target target, World world, Actor firedBy) { if (target.Type == TargetType.Actor) @@ -117,30 +118,31 @@ namespace OpenRA.GameRules return false; } + ///Checks if the weapon is valid against (can target) the actor. public bool IsValidAgainst(Actor victim, Actor firedBy) { - if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy))) - return false; - var targetable = victim.TraitOrDefault(); if (targetable == null || !ValidTargets.Intersect(targetable.TargetTypes).Any() || InvalidTargets.Intersect(targetable.TargetTypes).Any()) return false; - return true; - } - - public bool IsValidAgainst(FrozenActor victim, Actor firedBy) - { - // Frozen Actors are treated slightly differently. if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy))) return false; + return true; + } + + ///Checks if the weapon is valid against (can target) the frozen actor. + public bool IsValidAgainst(FrozenActor victim, Actor firedBy) + { var targetable = victim.Info.Traits.GetOrDefault(); if (targetable == null || !ValidTargets.Intersect(targetable.GetTargetTypes()).Any() || InvalidTargets.Intersect(targetable.GetTargetTypes()).Any()) return false; + if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy))) + return false; + return true; } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 7653a6cb5c..53f50e0b6a 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -22,7 +22,14 @@ namespace OpenRA.Traits // depends on the order of pips in WorldRenderer.cs! public enum PipType { Transparent, Green, Yellow, Red, Gray, Blue, Ammo, AmmoEmpty }; public enum TagType { None, Fake, Primary }; - public enum Stance { Enemy, Neutral, Ally }; + + [Flags] + public enum Stance + { + Enemy = 1, + Neutral = 2, + Ally = 4, + } [Flags] public enum ImpactType diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs index 60da52fa67..461951cff4 100644 --- a/OpenRA.Utility/UpgradeRules.cs +++ b/OpenRA.Utility/UpgradeRules.cs @@ -573,7 +573,7 @@ namespace OpenRA.Utility newYaml.Add(new MiniYamlNode("Size", newValue)); } - var keywords = new List{ "Damage", "InfDeath", "PreventProne", "ProneModifier", "Delay" }; + var keywords = new List { "Damage", "InfDeath", "PreventProne", "ProneModifier", "Delay" }; foreach(var keyword in keywords) { @@ -609,7 +609,7 @@ namespace OpenRA.Utility newYaml.Add(new MiniYamlNode("Spread", newValue)); } - var keywords = new List{ "Damage", "InfDeath", "PreventProne", "ProneModifier", "Delay" }; + var keywords = new List { "Damage", "InfDeath", "PreventProne", "ProneModifier", "Delay" }; foreach(var keyword in keywords) { @@ -636,7 +636,7 @@ namespace OpenRA.Utility var newYaml = new List(); - var keywords = new List{ "Spread", "Damage", "InfDeath", "PreventProne", "ProneModifier", "Delay" }; + var keywords = new List { "Spread", "Damage", "InfDeath", "PreventProne", "ProneModifier", "Delay" }; foreach(var keyword in keywords) { @@ -665,7 +665,7 @@ namespace OpenRA.Utility var newYaml = new List(); - var keywords = new List{ "Size", "Delay", "ValidTargets", "InvalidTargets" }; + var keywords = new List { "Size", "Delay", "ValidTargets", "InvalidTargets" }; foreach(var keyword in keywords) { var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword); @@ -683,7 +683,7 @@ namespace OpenRA.Utility var newYaml = new List(); - var keywords = new List{ "AddsResourceType", "Size", "Delay", "ValidTargets", "InvalidTargets" }; + var keywords = new List { "AddsResourceType", "Size", "Delay", "ValidTargets", "InvalidTargets" }; foreach(var keyword in keywords) { @@ -702,7 +702,7 @@ namespace OpenRA.Utility var newYaml = new List(); - var keywords = new List{ "SmudgeType", "Size", "Delay", "ValidTargets", "InvalidTargets" }; + var keywords = new List { "SmudgeType", "Size", "Delay", "ValidTargets", "InvalidTargets" }; foreach(var keyword in keywords) { @@ -722,7 +722,7 @@ namespace OpenRA.Utility var newYaml = new List(); - var keywords = new List{ "Explosion", "ImpactSound", "Delay", "ValidTargets", "InvalidTargets", "ValidImpactTypes", "InvalidImpactTypes" }; + var keywords = new List { "Explosion", "ImpactSound", "Delay", "ValidTargets", "InvalidTargets", "ValidImpactTypes", "InvalidImpactTypes" }; foreach(var keyword in keywords) { @@ -743,7 +743,7 @@ namespace OpenRA.Utility var newYaml = new List(); - var keywords = new List{ "WaterExplosion", "WaterImpactSound", "Delay", "ValidTargets", "InvalidTargets", "ValidImpactTypes", "InvalidImpactTypes" }; + var keywords = new List { "WaterExplosion", "WaterImpactSound", "Delay", "ValidTargets", "InvalidTargets", "ValidImpactTypes", "InvalidImpactTypes" }; foreach(var keyword in keywords) { diff --git a/mods/cnc/weapons.yaml b/mods/cnc/weapons.yaml index 4fdbdae7f1..21c51aad4b 100644 --- a/mods/cnc/weapons.yaml +++ b/mods/cnc/weapons.yaml @@ -147,28 +147,24 @@ Atomic: IonCannon: ValidTargets: Ground, Air Warhead@1Dam_impact: SpreadDamage - Spread: 1c0 + Range: 0, 1c1, 2c1, 2c512 Damage: 100 - Falloff: 1000, 368, 135, 50, 18, 7, 0 + Falloff: 1000, 1000, 250, 100 InfDeath: 5 ValidTargets: Ground, Air - Warhead@2Res_impact: DestroyResource - Warhead@3Smu_impact: LeaveSmudge + Warhead@2Smu_impact: LeaveSmudge SmudgeType: Scorch - Warhead@4Res_area: DestroyResource - Size: 2,1 - Delay: 3 - Warhead@5Smu_area: LeaveSmudge - SmudgeType: Scorch - Size: 2,1 - Delay: 3 - Warhead@6Res_area2: DestroyResource - Size: 1 - Delay: 3 - Warhead@7Smu_area2: LeaveSmudge + Warhead@3Smu_area: LeaveSmudge SmudgeType: Scorch Size: 1 Delay: 3 + Warhead@4Res_area2: DestroyResource + Size: 2 + Delay: 6 + Warhead@5Smu_area2: LeaveSmudge + SmudgeType: Scorch + Size: 2,1 + Delay: 6 Sniper: Report: RAMGUN2.AUD